打造 Go 语言最快的排序算法

动手点关注 干货不迷路 👆

前言

说到排序算法,很多同学会想起快速排序、堆排序、冒泡排序这些耳熟能详的算法。了解得深一些的同学,也可能看过例如 Python 的 timsort 以及 C++ intro sort 之类的排序算法。

但是我们也会有很多疑问,例如 Go 语言中使用的快速排序和我们书上学到的快速排序有什么区别呢?如果我们自己写一个快排,会比 Go 语言自带的快吗?排序算法方面业界最新的进展是什么呢,有没有一个算法是最快的?

本篇文章会向大家介绍字节跳动-语言团队在 Go 语言排序算法的实践,我们使用了 pdqsort 算法 + Go1.18 泛型,实现了一个比标准库 API 在几乎所有情况下快 2x ~ 60x 的算法库。

此项改动已经被社区采纳合并进入 Go runtime 当中,成为默认的 unstable 排序算法,预计将会在 Go 1.19 中和大家见面,其中非泛型版本位于标准库 sort,泛型版本位于 exp/slices。

Proposal: https://github.com/golang/go/issues/50154

临时项目地址:https://github.com/zhangyunhao116/pdqsort

简介

Go、Rust、C ++ 的默认 unstable 排序算法虽然名义上叫快速排序(quicksort),但其实质是混合排序算法(hybrid sorting algorithm),它们虽然在大部分情况下会使用快速排序算法,但是也会在不同情况下切换到其他排序算法。

unstable 排序算法意味着在排序过程中,值相等的元素可能会被互相交换位置。

一般来说,常见的混合排序算法,都会在元素较少(这个值一般是 16 ~ 32)的序列中切换成插入排序(insertion sort),尽管插入排序的时间复杂度为 O(n^2),但是其在元素较少时性能基本超越其他排序算法,所以在混合排序算法的方案中被经常使用。

在其他情况下,默认使用快速排序算法。然而,快速排序算法有可能因为 pivot 选择的问题(有些序列 pivot 选择不好,导致性能下降很快)而导致在某些情况下可能到达最坏的时间复杂度 O(n^2),为了保证快速排序算法部分在最坏情况下,我们的时间复杂度仍然为 O(n* logn)。大部分混合排序算法都会在某种情况下转而使用堆排序,因为堆排序在最坏情况下的时间复杂度仍然可以保持 O(n* logn)。

一言以蔽之,目前流行的 unstable 排序算法基本都是在不同的情况下,使用不同的方式排序从而达到最优解。而我们今天介绍的 pdqsort 也是这一思想的延伸。

前置知识

介绍一些常见的基本的排序算法以及它们的特性。

Quicksort (classic)

Average-case:O(n*logn) Bad-case:O(n^2)

经典的 快速排序(quicksort) 主要采用了分治的思想,具体的过程是将一个 array 通过选定一个 pivot(锚点)分成不同的 sub-arrays,选定 pivot 后,使得这个 array 中位于 pivot 左边的元素都小于 pivot,位于 pivot 右边的元素都大于 pivot。由此,pivot 两边构成了两个 sub-arrays,然后对这些 sub-arrays 进行相同的操作(选定 pivot 然后切分)。当某个 sub-array 只有一个元素时,其本身有序,此时便可以退出循环。如此反复,最后得到整体的有序。

我们可以观察到,经典的 quicksort 主要过程就是两步:

  • choose pivot: 选择一个 pivot

  • partition: 使用 pivot 对 array 进行划分

总的来说,quicksort 的性能关键点在于选定 pivot,选择 pivot 的好坏直接决定了排序的速度,如果每次 pivot 都被选定为真正的 median(中位数),此时快排的效率是最高的。因此 pivot 的选择重点在于寻找 array 真正的 median,目前所有的 pivot 选择方案都是在寻找一个近似的 median。

为什么 pivot 选定为中位数使得快排效率最高?

详细解释可以参考:https://en.wikipedia.org/wiki/Quicksort#Formal_analysis。简单来说,pivot 如果选定为中位数,则大部分情况下每次 partition 都会形成两个长度基本相同的 sub-arrays,我们只需要 logn 次 partition 就可以使得 array 完全有序,此时时间复杂度为 O(n* logn)。在最坏情况下,我们需要 n-1 次 partition (每次将长度为 L 的 array 分为长度为 1 和 L - 1 的两个 sub-arrays)才能使得 array 有序,此时时间复杂度为 O(n^2)。

我们为何不直接寻找 array 真正的 median?

原因是因为 array 的长度太长的话,寻找真正的 median 是一个非常昂贵的操作(需要存储所有的 items),相比于寻找一个近似的 median 作为 pivot 会消耗更多的资源,如果找到正确 median 的消耗比使用一个近似 median 高的话,这就是一个负优化。折中的方案就是使用一个高性能的近似 median 选择方案。

基本所有针对 quicksort 的改进方案,都是通过改造这两步得到的,例如第一步可以使用多种不同的 pivot 选择方案(见附录),第二步则有诸如 BlockQuickSort 这样通过减少分支预测来提升性能的方案。

Insertion sort

插入排序的主要想法是,每一次将一个待排序的元素插入到前方已经排序好的序列中,直到插入所有元素。尽管其平均时间复杂度高达 O(n^2),但是在 array 长度较短(这个值一般是 16 ~ 32)的情况下,在实际应用中拥有良好的性能表现。

Heap sort

堆排序是利用堆结构设计出来的一种排序算法。这个算法有一个非常重要的特性,其在最坏情况下的时间复杂度仍然为 O(n* logn)。故而很多混合排序算法利用了这一特性,将堆排序作为 fall back 的排序算法,使得混合排序算法在最坏情况下的理论时间复杂度仍然为 O(n* logn)。

pdqsort (pattern-defeating quicksort)

论文地址:https://arxiv.org/pdf/2106.05123.pdf

pdqsort (pattern-defating quicksort) 是 Rust、C++ Boost 中默认的 unstable 排序算法,其实质为一种混合排序算法,会在不同情况下切换到不同的排序机制,是 C++ 标准库算法 introsort 的一种改进。可以认为是 unstable 混合排序算法的较新成果。

其理想情况下的时间复杂度为 O(n),最坏情况下的时间复杂度为 O(n* logn),不需要额外的空间。

pdqsort 的主要改进在于,其对 common cases (常见的情况)做了特殊优化。因此在这些情况下性能超越了之前算法,并且相比 introsort 在随机序列的排序性能基本保持了一致。例如当序列本身有序、完全逆序、基本有序这些情况下都超越了大部分算法。其主要的思想是,不断判定目前的序列情况,然后使用不同的方式和路径达到最优解。

这里的算法细节描述的是 https://github.com/zhangyunhao116/pdqsort 中的实践,其大致相当于论文中的 PDQ 算法(没有来自 BlockQuickSort 的优化),并且加入了一些参数调整以及借鉴了部分其他 pdqsort 的实践优化。

注意,不同 pdqsort 实践中会有一些细微差异(因为语言以及接口的关系),不过其总体思想是一致的。

fcb62c4fae1cf2926c225e61ac2662bd.png

pdqsort C++ 版本性能对比,位于 https://github.com/orlp/pdqsort

整体流程

为了更好地解析 pdqsort 算法,我们先来描述下其主要流程。pdqsort 就是下面三种情况的不断循环,根据序列长度以及是否是最坏情况,每个 array 都会使用下面三种方法之一进行排序(有优先级,尽可能使用排在前面的方式)

  1. 短序列情况,对于长度在 [0, MAX_INSERTION] 的输入,使用 insertion sort (插入排序)来进行排序后直接返回,这里的 MAX_INSERTION 我们在 Go 语言下的性能测试,选定为 24。

  2. 最坏情况,如果发现改进的 quicksort 效果不佳(limit == 0),则后续排序都使用 heap sort 来保证最坏情况时间复杂度为 O(n*logn)。

  3. 正常情况,对于其他输入,使用改进的 quicksort 来排序,这里的算法分几步,后续内容会详细介绍部分步骤。

c027470c88ac87d95335479277cd502b.png

图中浅黄色虚线框代表此步骤为可选项,即算法会根据情况(以下变量)来决定是否执行。

下列变量代表 pdqsort 进行本次循环排序的情况,用于帮助算法来猜测需要排序的 array 的状态,来决定某些步骤是否需要进行

  • wasBalanced: Bool, 代表上次 partition 是否平衡。在 pivot 和真正的 median 很接近时我们认为是平衡的(true),此变量可以用 partition 后的 pivot index 同 array 两端的距离来判定。

  • wasPartitioned: Bool, 如果为真,则代表上次 partition 没有交换任何元素(即上次 partition 分割的是一个本身已经有序的 array)。

  • limit: int,如果为 0,则后续对 unsorted array 的排序都会使用 heap sort 而不是 quick sort。这种情况发生在 quicksort 有很多次选择的 pivot 和真正的 median 差距很大,从而导致 partition 后的两个 sub-arrays 长度相差较大的场景中。limit 的初始值是根据待排序 array 的长度计算出来的,每次发现快排策略效果不佳时,即 !wasBalanced 为真,则使得 limit 减小 1。

3-1. 应对可能的最坏情况,即实现中的breakPatterns。此时会判断 wasBalanced 是否为 true,如果不平衡(false),则随机交换几个元素,破坏一些可能造成 pivot 与 median 相差较大的特殊情况。

3-2. pivot 的选择,即实现中的 choosePivot。函数同时返回两个值,pivotidx 和 likelySorted,前者是 pivot 在此 array 的 index(索引),后者代表着选择 pivot 的过程中,是否可以大概率认定这个 array 已经为有序。

3-3. 应对几乎有序的情况,即实现中的 partialInsertionSort。如果 wasBalanced && wasPartitioned && likelySorted 为 true,则代表此 array 有非常大的可能是一个有序序列。此时我们使用 partial insertion sort 的排序算法,其原理和 insertion sort 大致相当,只是多了一个尝试次数,即只会对有限的元素进行插入排序,增加这个限制是为了避免猜测错误导致消耗大量时间。如果达到尝试次数时 array 仍未有序,则退出。如果在尝试次数之前发现所有元素有序,则可以直接返回。

3-4. 应对重复元素较多的情况,即实现中的 partitionEqual 。如果 pred 存在,并且和本次选中的 pivot 值相等(pred 是之前 array 的 pivot,即目前 array 中的最小值,因为与 pivot 重复的元素只可能出现在 partition 后的两个 sub-arrays 其中之一),说明重复元素很可能较多,则调用 partitionEqual 然后继续进行下次循环,使用这种方法将重复元素提前放到一起,因为多次选定重复元素作为 pivot 会使得 partition 的效率较低。

3-5. partition,使用 pivot 来分割 array,即实现中 partition。此函数和一般快排的 partition 相比基本相同,区别在于其会检测序列是否本身就是有序的(即 partition 时没有交换任何元素)。

实现细节

breakPatterns (3-1)

这一步的作用是解决一些会导致现有 pivot 选择方案表现很差的情况,所以当上次 partition 的 pivot 选择不好时(表现为最终 pivot 的位置离 array 两端之一很近),此时会随机交换几个元素来避免一些极端情况。同时,此步骤还会将 limit 减去 1,说明上次 pivot 的选取方案不够好(当 limit 为 0 时使用 heapsort 而不是快排方案来进行排序)。

pivot 选择 (3-2)

附录中有关于 pivot 选择方案的详细介绍。

假设 array 的长度为 L,SHORTEST_MEDIAN_OF_MEDIANS 值为 50。这里根据长度分为三种情况:

  1. L 位于 [0,8): 直接取固定值作为 pivot,即 L/4 * 2

  2. L 位于 [8,SHORTEST_MEDIAN_OF_MEDIANS): 使用 medians of three 方法采样 3 个元素筛选 pivot,即 L/4* 1 L/4* 2 L/4* 3 的中间值

  3. L 位于 [SHORTEST_MEDIAN_OF_MEDIANS, ∞): 使用 Tukey’s median of medians 采样 9 个元素得到一个近似中间值

此方法还会判断这个 array 是否很可能已经有序,例如当第三种情况时,如果发现 a a-1 a+1 这三个值中,a 恰好是中间值(b,c 也同样如此),则说明元素在这些地方都局部有序,所以这个 array 很可能是已经有序的。如果每次都发现,a a-1 a+1 这三个值都是逆序排列(b,c 也同样如此),则说明元素在这些地方都局部逆序,整个 array 很可能是完全逆序的。此时的策略是将整个 array 翻转,这样有很大概率使得整个 array 几乎有序。

Go 语言环境下的实践考量

Go 1.18 泛型对于排序算法的影响

Go 1.18 的泛型在这种情况下有较大的性能提升并且增加了可维护性,同样的算法在经过泛型改造后能得到 2x 的性能提升。这一点我们通过观察 pdqsort 泛型版本,以及 pdqsort (with sort.Interface) 的版本性能对比可以观察出来。

在可维护性方面,通过泛型的类型约束抽象了所有可比对的基本类型,不需要使用复杂的代码生成技术。

在性能方面,泛型由于有了类型参数,可以在编译期生成大量代码,免去了使用 sort.Interface 带来的抽象开销。

pdqsort 相比于 Go 原有算法的优势

在纯粹的算法层面,即 pdqsort (with sort.Interface) ,pdqsort 在完全随机的情况下和原有算法(类似于 IntroSort)性能几乎一致(非泛型版本,因为需要兼容 sort.Interface)。在常见的场景下(例如序列有序|几乎有序|逆序|几乎逆序|重复元素较多)等情况下,会比原有的算法快 1 ~ 30 倍。

因此,我们同样向 Go 官方提议将 pdqsort 应用在 sort.Sort 中,相关的 issue 讨论位于:https://github.com/golang/go/issues/50154

Go 原有的算法类似于 introsort,其通过递归次数来决定是否切换到 fall back 算法,而 pdqsort 使用了另一种计算方式(基于序列长度),使得切换到 fall back 算法的时机更加合理。

为什么禁用来自 BlockQuickSort 的优化

因为 BlockQuickSort 的优化基本来自减少分支预测,原理是在 partition 一个长序列的时候,先存储需要交换的元素,后续统一放到真正的序列中。经过实际性能测试,发现这一优化在 Go 上并不成立,甚至是一个负优化。原因可能由于 Go 是一门 heap-allocate 的语言,对于此类优化并不敏感。并且对于减少分支预测,Go 的编译器在某些情况下并不能优化到相应指令(CMOV)。

总结

目前大部分工业界使用的 unstable 排序算法,基本上都从过去教科书中单一的排序算法转变成混合排序算法,来应对实践场景中各式各样的序列。

pdqsort 依靠其在常见场景相比之前算法的性能优势,逐渐成为 unstable 排序算法的主流实现。基于 Go1.18 带来的泛型,使得排序算法的实现被大大简化,也给予了我们实现新算法的可能。但是 pdqsort 也不是万能灵药,在某些情况下,其他的算法依然保持着优势(例如 Python 标准库的 timsort 在混合升序&&降序的场景优于 pdqsort)。不过在大部分情况下,pdqsort 依靠其对于不同情况的特定优化,成为了 unstable 算法较好的选择。

附录

quicksort pivot 方案对比

这里简单介绍不同的 pivot 选择方案。最好的 pivot 选择方案就是使用一个高性能的近似 median 选择方案,在准确度和性能上达到平衡。假设我们需要排序的元素为 [4,3,2,1],我们需要将其排列为升序,即 [1,2,3,4]。

选择首个元素

这是我们实现快排时最简单的方法,即选取 array 的首个元素作为 pivot。

  • [4,3,2,1]。选定 4 为 pivot,由于左边没有元素,所以会从最右边开始找,找到第一个比 4 小的元素,即 1 作交换。

  • [1,3,2,4]。选定 1 为 pivot,同理。希望从右边找到第一个比 1 小的元素,由于 1 已经是最小的值,此轮不会交换任何元素。

  • [1,3,2,4]。选定 3 为 pivot,同理。将 2 和 3 互换。

  • [1,2,3,4]。得到结果。

可以看到,选择首个元素的方式在 array 为逆序的情况下,每轮 partition 只将问题的规模减小了 1,即每次只能确定一个元素的最终位置。这种简单的方法在面对极端情况时效果并不好,在完全逆序的情况下达到了快排的最坏情况。

median of three

这个方法是分别取最左边、最右边、中间三个值,然后选出其中间值作为 pivot。例如 [4,3,2,1],我们会选取 4 3 1 然后选择其中的 3 作为 pivot。这种方式相比于首个元素的方式会更加合理,因为采样了多个元素,不容易受到一些极端情况的影响,往往会比首个元素的方式有更好的效果。

stackoverflow discussion:

https://stackoverflow.com/questions/7559608/median-of-three-values-strategy

median of medians

这个方法的原理其实和 median of three 相似,不同的地方在于加大了 pivot 的采样范围,在 array 长度较长的情况下理论表现会更好。其采样步骤是先将 array 分为 n/5 个 sub-arrays,n 为 array 的长度。然后将这些 sub-arrays 的 medians 都取出,选取这些 medians 中的 median,同样的方式如此反复,最后得到一个 median of medians 作为最后的 pivot。

stackoverflow discussion:

https://stackoverflow.com/questions/5605916/quick-sort-median-selection

Median-finding Algorithm:

https://brilliant.org/wiki/median-finding-algorithm/#citation-1

John Tukey’s median of medians

此方法其实是 median of three 的改进,我们在 median of three 会取三个元素,而 Tukey’s median of medians 会取三个元素及其相邻两个元素的 median(例如 median of three 取了 a,b,c 则此方案会选择 a-1 a a+1 取这三个值的 median),然后再取这个三个 medians 的 median。即此方案会采样其中 9 个元素,相比于 median of three 多了三倍的采样率,所以此方法也叫做 Tukey’s ninther。

See

https://www.johndcook.com/blog/2009/06/23/tukey-median-ninther/

加入我们

字节跳动语言团队致力于解决公司内部大规模集群中程序语言相关的各种问题,让 Go, Python, Java, node.js 和 C/C++ 等多种语言更好的有机结合在一起,利用每种语言独立的特性更好的发挥它们各自的长处。

我们正在寻求优秀的同学加入!

  • 程序语言工程师:https://jobs.bytedance.com/experienced/position/6839595594768451854/detail

  • 性能分析优化平台研发工程师:https://jobs.bytedance.com/experienced/position/6934121570337032462/detail

相关推荐

2024 抖音欢笑中国年(五):Wasm、WebGL 在互动技术中的创新应用

前言随着 Web 前端技术的不断发展,越来越多的新兴技术方案被引入到 Web 开发中,其中 Wasm 和 WebGL 作为前端领域的两大利器,为开发者带来了更多的可能性。本文将结合2024 年抖音欢笑中国年的部分项目,重点介绍如何利用 Wasm 和 WebGL 对目前流行的一些前端互动技术(比如 Lottie、渲染引擎、动画图片等)进行创新和实践,利用 Wasm 和 WebGL 等新技术方案的特性...

字节跳动技术团队官方博客 2万+

2024 抖音欢笑中国年(四):渲染技术实践与探索

作者:陈瑞、欧阳浩铸、王武俊、倪梵云前言抖音在2024年春节期间推出了欢笑中国年系列活动,为用户带来了全新的体验和乐趣。而SAR Creator则为该项目研发工作提供了重要的技术支持。SAR Creator是一款基于 Typescript 的高性能、轻量化的互动解决方案,目前支持了浏览器和跨端框架平台,服务于字节内部的各种互动业务。这些绚烂多彩的互动场景当然也离不开实时渲染技术的支持,因此本文将专...

字节跳动技术团队官方博客 2万+

2024 抖音欢笑中国年(三):编辑器技巧与实践

前言本次春节活动中,我们大部分场景使用内部的 SAR Creator互动方案来实现。SAR Creator 是一款基于 TypeScript 的高性能、轻量化的互动解决方案,目前支持了Web和字节内部跨端框架平台,服务于字节内部的各种互动业务,包括但不限于抖音春节、抖音直播礼物、抖音UG活动等。SAR Creator 编辑器支持了图形化界面,提供了各类完善的系统(光照、动画、脚本等)供用户快速便捷...

字节跳动技术团队官方博客 1万+

2024 抖音欢笑中国年(二):AnnieX互动容器创新玩法解析

本文基于24年抖音春节活动业务背景,介绍了字节跨端容器AnnieX在游戏互动套件上的探索,致力于提升容器在游戏互动场景的优化能力。业务背景AnnieX作为字节一方游戏统一容器,服务字节内部电商、直播、UG等跨端场景业务。在字节一方游戏互动场景,有大量的一方游戏业务对容器有特定的流量、端能力和游戏优化的诉求。因此我们不断深入互动游戏业务特点,为字节游戏提供完善游戏端能力和流量运营能力,同时提供游戏互...

字节跳动技术团队官方博客 1万+

2024 抖音欢笑中国年(一):招财神龙互动技术揭秘

字节跳动旗下的抖音等 App 在 2024 年春节期间推出了欢笑中国年系列活动,在实现增长业务目标的同时,为用户带来了全新的体验和乐趣。「招财神龙」是其中的一个重要玩法。前言本次春节活动,使用到了字节内的主要前端、跨端、互动技术产品。主要涉及:跨端框架提供了首屏直出的方案使其具有较短的首屏时间,能够大大提升业务加载成功率。跨端框架也提供了 Canvas 作为 SAR Creator 等渲染引擎的...

字节跳动技术团队官方博客 1万+

Monorepo 解决方案 — 基于 Bazel 的 Xcode 性能优化实践

背景介绍书接上回《Monorepo 解决方案 — Bazel 在头条 iOS 的实践》,在头条工程切换至 Bazel 构建系统后,为了支持用户使用 Xcode 开发的习惯,我们使用了开源项目 Tulsi 作为生成工具,用于将 Bazel 工程转换为 Xcode 工程。但是在使用的过程中,我们发现了一些问题,其中影响较大的是,Xcode 工程卡顿:对于头条这种大型项目来说,Xcode 卡顿一直是本地...

字节跳动技术团队官方博客 1万+

抖音 ANR 自动归因平台建设实践

背景介绍本文在 2024 年初最新一期『抖音客户端基础技术大揭秘』技术沙龙活动中已做过专题分享,本次将内容重新整理文章进行分享。公众号后台回复技术沙龙可查看沙龙回放及 PPT~抖音作为一个超大型的应用,我们在 ANR 问题治理上面临着很大的挑战。首先对于存量问题的优化,由于缺少有效的归因手段,一些长期的疑难问题一直难以突破解决,例如长期位于 Top 1 的 nativePollOnce 问题。同时...

字节跳动技术团队官方博客 2万+

CVPR 2024 | CAMixerSR 动态注意力分配的超分辨率加速框架

背景随着相关技术和应用的发展,比如超高清屏幕、虚拟现实(VR)等沉浸式体验的增加,用户对超高分辨率图像和视频的需求变得越来越强烈。在这些场景中,图像的质量和清晰度对于提供最佳的用户体验至关重要。超高分辨率不仅能提供更清晰、更真实的视觉效果,还能在一定程度上增强人们的互动和沉浸感,在一些VR场景中我们需要8K甚至16K的才可以满足需求。然而要生成或者处理这些超高分辨率的内容,对算力的要求也是与日增长...

字节跳动技术团队官方博客 1万+

CVPR 2024 | Modular Blind Video Quality Assessment:模块化无参视频质量评估

无参视频质量评估 (Blind Video Quality Assessment,BVQA) 在评估和改善各种视频平台并服务用户的观看体验方面发挥着关键作用。当前基于深度学习的模型主要以下采样/局部块采样的形式分析视频内容,而忽视了实际空域分辨率和时域帧率对视频质量的影响,随着高分辨率和高帧率视频投稿逐渐普及,特别是跨分辨率/帧率视频转码档位画质评估场景中,这种影响变得更加不可忽视。在本文中,我们...

字节跳动技术团队官方博客 1万+

2024 AI & 前端:回首展望,光芒未至,破晓之前!

前言回望 2023 年,ChatGPT 的突然爆火,让 AI 无疑成为最为值得注目的新兴领域之一,我们也一起见证了生成式 AI 的寒武纪大爆发。这一年来,国内外的生成式 AI 、大模型和相关产品以令人眼花缭乱的速度更新迭代,新的创业浪潮风起云涌。在这 AI 浪潮下,也让我们有了新的开发思考,探索着在各个环节中“前端 & AI”的应用场景。勇于探索的前端开发者们已经开始挥舞着 AI 的“魔法...

字节跳动技术团队官方博客 1万+

Kotlin 云端差分缓存技术

本文由字节跳动 Buildinfra 团队出品。在我们的工程上线 Monorepo 全源码后,Kotlin 编译成了整个编译中最耗时的步骤,全源码过程中大量的 BuildCache Miss 导致我们的编译数据落后原来多仓二进制时代很多,且业界没有相关的解决方案。本篇文章我们来具体阐述下 BuildInfra 团队自研的解决方案 - Kotlin 云端差分方案的原理和技术实现。一、Monorepo...

字节跳动技术团队官方博客 1万+

字节跳动基础架构SRE-Copilot获得2023 CCF国际AIOps挑战赛冠军

近日,2023 CCF国际AIOps挑战赛决赛暨“大模型时代的AIOps”研讨会在北京成功举办,活动吸引了来自互联网、运营商、科研院所、高校、软硬件厂商等领域多名专家学者参与,为智能运维的前沿学术研究、落地生产实践打开了新思路。决赛中,从初赛两百多支队伍中脱颖而出的十支入围队伍分别展示了各自的方案,并进行了现场答辩,评审专家从选题方向、创新性、实用性、完整度和实验复现结果等多角度进行了综合评定,最...

字节跳动技术团队官方博客 2万+

字节跳动百万级Metrics Agent性能优化的探索与实践

背景metricserver2 (以下简称Agent)是与字节内场时序数据库 ByteTSD 配套使用的用户指标打点 Agent,用于在物理机粒度收集用户的指标打点数据,在字节内几乎所有的服务节点上均有部署集成,装机量达到百万以上。此外Agent需要负责打点数据的解析、聚合、压缩、协议转换和发送,属于CPU和Mem密集的服务。两者结合,使得Agent在监控全链路服务成本中占比达到70%以上,对Ag...

字节跳动技术团队官方博客 1万+

西瓜视频RenderThread引起的闪退问题攻坚历程

背景影响西瓜之前存在过一类RenderThread闪退,从堆栈上看,全部都是系统so调用,给人的第一印象像是一个系统bug,无从下手。闪退集中在Android 5~6上,表现为打开直播间立即闪退。该问题在2022年占据Native Crash Top5,2023年更是上升到到Top1。因此有必要投入时间和精力再重新审视一下这个问题。在历经多周的源码分析和排查后,逐步明确了问题根因并修复,最终取得了...

字节跳动技术团队官方博客 2万+

字节电商双11 大促容量保障是如何做的?

前言Rhino 简介Rhino是字节自研全链路容量评估产品,致力于构建完整的全链路容量评估解决方案(覆盖:容量预估->资源准备->数据准备->容量验证->监控->分析->决策->处理反馈);围绕容量在稳定性、成本、效率 三方面提供业务全方位基础支撑。Rhino 目前已经成为字节各业务容量评估主流解决方案,并且历年来在业务大型活动稳定性保障中(抖音春节项目、...

字节跳动技术团队官方博客 10万+

使用火山引擎 APMPlus 解决抖音Top 1 Java 崩溃的通用优化方案

背景近3个月,抖音 Android 版面临一个多次触发线上报警的崩溃问题,全量版本和灰度版本的异常数据激增,该问题不仅容易触发报警,更成为了 Java Top 1 崩溃问题,带来巨大困扰,急需攻坚解决。本文展现了具体的分析过程、优化思路和解决方案,同时提供了已集成该方案的实用工具。初步分析多维特征我们以某发版期间数据为例进行分析:机型方面:比较分散,有聚集部分samsung sm-s9180 占比...

字节跳动技术团队官方博客 2万+

用 Addon 增强 Node.js 和 Electron 应用的原生能力

前言Node.js Addon 是 Node.js 中为 JavaScript 环境提供 C/C++ 交互能力的机制。其形态十分类似 Java 的 JNI,都是通过提供一套 C/C++ SDK,用于在 C/C++ 中创建函数方法、进行数据转换,以便 JavaScript / Java 等语言进行调用。这样编写的代码通常叫做 Bindings。此外还有基于 C ABI Calling Convent...

字节跳动技术团队官方博客 2万+

火山引擎 ByteHouse 的增强型数据导入技术实践

作为企业数字化建设的必备要素,易用的数据引擎能帮助企业提升数据使用效率,更好提升数据应用价值,夯实数字化建设基础。数据导入是衡量OLAP引擎性能及易用性的重要标准之一,高效的数据导入能力能够加速数据实时处理和分析的效率。作为一款OLAP引擎,火山引擎云原生数据仓库ByteHouse源于开源ClickHouse,在字节跳动多年打磨下,提供更丰富的能力和更强性能,能为用户带来极速分析体验,支撑实时数据...

字节跳动技术团队官方博客 1万+

打造企业级智能问答系统的秘密:如何使用云数据库 PostgreSQL 版实现向量检索

本文就如何利用火山引擎云数据库 PostgreSQL 版和大语言模型技术(Large Language Model,简称 LLM),实现企业级智能交互式问答系统进行介绍。通过本文,你将会了解交互式问答系统的原理,学习 PostgreSQL 的向量化存储和检索技术,以及大语言模型交互技术等。背景在大数据的浪潮下,众多企业建立了自己的知识库,以便于信息检索和知识查询。然而,随着知识库内容的膨胀,传统的...

字节跳动技术团队官方博客 2万+

抖音大型直播的画质优化实践

面临挑战随着抖音内容生态的不断丰富,越来越多的大型赛事在抖音平台进行直播,世界杯/春晚/亚运会等各项赛事节目引来大量用户观看。卡塔尔世界杯期间,抖音提供的稳定高质直播画面为观众带来了完美的观赛体验,决赛的 PCU 高达 3700W+。不同赛事节目涉及链路众多,且不同赛事之间存在差异,如何保障各链路的画质稳定并进一步提升画质,是一个巨大的挑战。如何应对挑战?画质优化链路大型赛事直播涉及链路较长,不同...

字节跳动技术团队官方博客 2万+

抖音直播新一代BVC编码器正式亮相

面临挑战在直播行业发展如火如荼的今天,用户对视频体验的要求也水涨船高。视频基础体验的关键要素包括清晰度、流畅度、低延迟等,而这些要素的“第一性原理”,就是视频本身的编码效率,也就是压缩率。视频编码是整个技术体系的基座,编码效率的显著提升,能够在同等码率下极大提高画质,从而改善用户体验。视频编码效率的重要性不言而喻,但进一步地提升也并非易事,尤其在直播场景中,对编码速度、延迟、码率控制等方面都有很高...

字节跳动技术团队官方博客 7356

Go Metrics SDK Tag 校验性能优化实践

背景Metrics SDK 是与字节内场时序数据库 ByteTSD 配套的用户指标打点 SDK,在字节内数十万服务中集成,应用广泛,因此 SDK 的性能优化是个重要和持续性的话题。本文主要以 Go Metrics SDK 为例,讲述对打点 API 的 hot-path 优化的实践。用户在使用 SDK API 进行打点时,需要传入指标对应的 Tag:tags:=[]m.T{{Name:"foo...

字节跳动技术团队官方博客 1万+

云上智能驾驶三维重建最佳实践

智能驾驶技术的不断发展,正在改变着我们的出行方式和交通系统。作为其中的一个关键技术,三维重建在智能驾驶系统中起着重要的作用。除去车端本身的感知、重建算法,自动驾驶技术的落地与发展需要庞大的云端重建能力支撑,火山引擎多媒体实验室通过行业领先的自研三维重建技术,结合强大的云平台资源与能力,助力相关技术在云端大规模重建、自动标注、真实感仿真等场景的落地与应用。本文重点介绍火山引擎多媒体实验室三维重建技术...

字节跳动技术团队官方博客 6305

火山引擎实时、低延时拥塞控制算法的优化实践

摘要火山引擎智能拥塞控制算法 VICC(Volcano Intelligent Congestion Control)是一种自适应的拥塞控制算法,旨在解决全球不同网络环境下,不同音视频应用对带宽利用率和延时的差异化要求。它结合了传统拥塞控制算法(如 GCC 和 BBR)的优点,并且能够根据不同的网络条件、业务偏好和码率特征进行自适应调整,包括自适应拥塞响应速度、自适应带宽探测幅度、自适应丢包检测策...

字节跳动技术团队官方博客 6735

veImageX 演进之路:Web 图片加载提速50%

背景说明火山引擎veImageX演进之路主要介绍了veImageX在字节内部从2012年随着字节成长过程中逐步演进的过程,演进中包括V1、V2、V3版本并最终面向行业输出;整个演进过程中包括服务端、客户端、网络库、业务场景与优化等多个角度介绍在图像处理压缩、省成本与体验优化的经验与方案;本篇文章重点介绍在web端演进和提供的能力,图片是 Web 站点中的重要元素,图片体积、格式、分辨率以及渲染方式...

字节跳动技术团队官方博客 6589

自研多模态追踪算法 PICO 为「手柄小型化」找到新思路

作者:张韬、林泽一 、闻超 、赵洋研发背景作为头戴的追踪配件,VR手柄可以通过HMD(头戴显示设备)的inside-out光学追踪定位原理,计算出手柄的空间运动轨迹,同时结合6轴传感器实现6DoF空间定位。与此同时,结合手柄控制器的物理按键、马达反馈、摇杆等,用户还能获得逼真、细腻的触觉反馈,进一步增强虚拟现实人机交互的能力以及沉浸感,这也是目前无手柄方案所难以实现的。目前主流VR手柄的追踪技术方...

字节跳动技术团队官方博客 7819

如何利用播放器节省20%点播成本

点播成本节省的点其实涉及诸多部分,例如:CDN、转码、存储等,而利用播放器降本却是很多客户比较陌生的部分。火山引擎基于内部支撑抖音集团相关业务的实践,播放器恰恰是成本优化中最重要和最为依赖的部分。火山引擎的视频团队做了份数据统计,在一个很经典的视频业务中,我们在2022年至2023年大约1年半的时间里,针对这个业务进行了33次成本优化点,其中13次是播放器主导的优化,其余的有12次也是需要播放器强...

字节跳动技术团队官方博客 6176

火山引擎 ByteHouse:ClickHouse 如何保证海量数据一致性

背景ClickHouse是一个开源的OLAP引擎,不仅被全球开发者广泛使用,在字节各个应用场景中也可以看到它的身影。基于高性能、分布式特点,ClickHouse可以满足大规模数据的分析和查询需求,因此字节研发团队以开源ClickHouse为基础,推出火山引擎云原生数据仓库ByteHouse。在日常工作中,研发人员经常会遇到业务链路过长,导致流程稳定性和数据一致性难保障的问题,这在分布式、跨服务的场...

字节跳动技术团队官方博客 6900

抖音集团都在用的画质评估工具,确定不试试吗?

导读本文从抖音集团内部画质评估体系的建设历程着笔,主要分享了画质评测对于业务的重要性、主要应用场景和内部产品的一些典型实践案例。通过分享业务视角遇到的一些问题和我们的解决思路,希望能抛砖引玉,为遇到类似困扰的伙伴们提供有价值的参考。画质评估体系建设历程为何评测画质如此重要?我们通过线上业务大量实验发现,图片画质优劣对点击率、 停留时长等消费类指标有正相关影响,间接影响用户收益指标。因此,建设一套行...

字节跳动技术团队官方博客 7940

VLDB 2023 | CDSBen: 字节跳动 veDB 数据库存储系统性能测试模型

背景随着业务爆炸式增长与云原生技术的日渐成熟,大量云原生分布式数据库产品如雨后春笋般涌现,其中一部分主打 OLTP 场景的分布式数据库强调的是从计算-存储分离架构获得弹性收益;对于业界各种计算-存储分离架构的数据库而言,怎么用真实的端到端数据库 workload 去 benchmark 其底层存储系统一直存在以下难题:对于数据库专用存储系统,不存在如 fio 一样的“事实标准” benchmark...

字节跳动技术团队官方博客 5896
上一篇: 一文读懂全球化系统中的日期时间处理问题
下一篇: 抖音 Android 性能优化系列:Java OOM 优化之 NativeBitmap 方案
 字节跳动技术团队
字节跳动技术团队 企业官方账号 企业官方账号
博客等级 码龄7年 8153粉丝 316原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值