前沿论文 | LLM推理性能优化最佳实践

原文:安全验证 - 知乎​

来源
题目:LLM Inference Performance Engineering: Best Practices
地址:https://www.databricks.com/blog/llm-inference-performance-engineering-best-practices

在这篇博文中,MosaicML工程团队分析了利用当下的开源大语言模型(LLM)进行生产部署的最佳实践。作者也基于这些模型提供了构建推理服务的指南,以帮助用户选择模型以及部署硬件。作者在生成环境中针对多种基于Pytorch的后端(比如FasterTransformers, vLLM, NVIDIA即将发布的TensorRT-LLM)进行了测试,这个指南也是基于此基础完成。

了解LLM文本生成

大型语言模型(LLM)通过两个步骤生成文本:

  1. 预填充(prefill):输入提示中的token被并行处理。
  2. 解码(decoding):文本采用自回归方式一次生成一个"token"。

每个生成的token都会附加到输入中,并反馈到模型中生成下一个token。当LLM输出一个特殊的停止token或满足用户定义的条件(如超过生成token的最大数量)时,生成就会停止。

Tokens可以是单词或分词;将文本分割成token的具体规则因模型而异。例如,您可以比较Llama模型和OpenAI模型如何将文本分割成token。虽然LLM推理提供商经常用基于token的指标(如tokens/秒)来衡量性能,但由于存在不同差异,这些衡量指标在不同模型类型之间常常不具备可比性。举个具体的例子,Anyscale团队发现Llama 2分词要比ChatGPT分词长19%(但总体成本仍然要低得多)。HuggingFace的研究人员还发现,在相同数量的文本中,Llama 2需要比GPT-4多花20%左右的token来进行训练。

LLM服务的重要指标

那么,应该如何考虑推理速度呢?

我们的团队使用四个关键指标来衡量LLM服务:

  1. 生成第一个token的时间(TTFT):用户输入查询后多久开始看到模型输出。在实时交互中,等待响应的时间越短越重要,但在离线工作负载中,等待响应的时间就没那么重要了。这一指标取决于处理提示和生成第一个输出token所需的时间。
  2. 生成每个输出token所需的时间(TPOT):为每个查询我们系统的用户生成一个输出token所需的时间。这一指标与每个用户如何感知模型的"速度"相对应。例如,TPOT为100ms/token,即为每个用户每秒生成10个token,或每分钟生成450个左右单词,这比一般人的阅读速度还要快。
  3. 延迟:模型为用户生成完整响应所需的总时间。整体响应延迟可通过前两个指标计算得出:延迟= (TTFT) + (TPOT)*(要生成的token数量)。
  4. 吞吐量:推理服务器每秒可为所有用户和请求生成的输出token数量。

我们的目标是什么?尽可能快地生成第一个token、最高的吞吐量以及输出每个token的时间尽可能短。换句话说,我们希望我们的模型能以最快的速度为尽可能多的用户生成文本。

值得注意的是,吞吐量和每个输出token所需的时间之间存在权衡:如果我们同时处理16个用户的查询,相比于按顺序进行查询,吞吐量会更高,但为每个用户生成输出token所需的时间会更长。

如果对整体的推理延迟有要求,以下是一些评估模型的有用建议:

  • 输出长度主导整体响应延迟:对于平均延迟,通常只需将预期或者最大输出token长度乘以模型每个输出token的整体平均时间。
  • 输入长度对性能影响不大,但对硬件要求很重要:在MPT模型中,增加512个输入token所增加的延迟比增加8个输出token所增加的延迟要少。但是,支持长输入的需求可能会增加模型的服务难度。例如,我们建议使用A100-80GB(或更新版本)为最大上下文长度为2048个token的MPT-7B提供服务。
  • 总体延迟与模型大小呈亚线性关系:在相同硬件条件下,模型越大速度越慢,但速度比率并不一定与参数量比率相匹配。MPT-30B的延迟是MPT-7B的2.5倍。Llama2-70B的延迟是Llama2-13B的2倍。

经常有潜在客户要求我们提供平均推理延迟。我们建议您在确定具体的延迟目标之前(类似于“我们需要每个token的延迟时间小于20毫秒"),先花一些时间确定您的预期输入和预期输出长度。

LLM推理面临的挑战

优化LLM推理的常见手段有如下这些:

  • 算子融合:将不同的相邻算子组合在一起,可以很好的降低延迟。
  • 量化:对激活和模型权重进行压缩,以使用更少的bit数。
  • 压缩:稀疏化或模型蒸馏。
  • 并行:跨多个设备的张量并行或针对大模型的流水线并行。

除了这些方法,还有许多针对Transformer的重要优化。

一个典型的例子就是KV(key-value)缓存。在仅基于解码器的Transformer模型中,Attention机制的计算效率很低。每个token都会依赖之前的所有token,因此在生成每个新的token时都存在大量的重复计算。例如,在生成第N个token时,(N-1)个token会关注第(N-2)、第(N-3)一直到第1个token。同样地,在生成第(N+1)个token时,第N个token也需要关注第(N-1)、第(N-2)、第(N-3)一直到第1个token。KV缓存,即为注意力层保存中间的K/V值方便后续复用,避免重复计算。

内存带宽是关键

LLM中的计算主要由矩阵乘运算主导。在大多数硬件上,这些小维度运算通常受内存带宽限制。当以自回归方式生成token时,激活矩阵的维度(由batch size和序列中的token数量定义)在batch size小的情况下很小。因此,速度取决于我们将模型参数从GPU内存加载到本地缓存或寄存器的速度,而不是加载数据后的计算速度。推理硬件内存带宽的利用率比其峰值算力更能预测token生成的速度。

就服务成本而言,推理硬件的利用率非常重要。GPU价格昂贵,因此我们需其做尽可能多的工作。通过共享推理服务,合并来自多用户的工作负载、填补单个计算流中的气泡和batching多个请求提高吞吐来降低成本。对于像Llama2-70B这样的大模型,只有在batch size较大时才能获得更好的性价比。拥有一个能在大的batch size下运行的推理服务系统对于成本效益至关重要。然而,大batch意味着更大的KV缓存,这反过来又增加了为模型提供服务所需的GPU数量。这就是一场拉锯战,共享服务运营商需要对成本进行权衡,并进行系统优化。

模型带宽利用率(MBU)

LLM推理服务器的优化程度如何?

如前文所述,在较小的batch size,LLM推理(尤其是在解码时)受限于我们如何将模型参数从设备内存加载到计算单元的速度。内存带宽决定了数据移动的速度。为了衡量底层硬件的利用率,我们引入了一个新指标,称为模型带宽利用率(MBU)。MBU的定义是(实际的内存带宽)/(峰值内存带宽),其中实际的内存带宽为((模型参数总大小+KV缓存大小)/TPOT)。

例如,如果以16 bit精度运行的7B参数的TPOT等于14毫秒,也就是在14毫秒内要移动 14GB的参数,相当于每秒使用1TB的带宽。如果机器的峰值带宽为2TB/秒,那么对应的MBU为50%。为简单起见,本示例忽略了KV缓存大小,因为对于较小的batch size和较短的序列长度来说,KV缓存较小。MBU值接近100%,意味着推理系统有效利用了可用的内存带宽。MBU还有助于以标准化方式比较不同的推理系统(硬件+软件)。MBU是对模型浮点计算利用率(MFU,在PaLM论文中介绍)指标的补充,其中MFU在compute bound的环境中非常重要

图1为MBU示例图,与roofline model类似。橙色区域的斜线表示在内存带宽100%完全饱和的情况下可能达到的最大吞吐量。然而,在实际情况中,对于小batch size(白点),观察到的性能会低于最大值--低多少是MBU的衡量标准。对于大batch size(黄色区域),系统是compute bound,所实现的吞吐量占峰值吞吐量的比例可以通过MFU来衡量。

图1:MBU(模型带宽利用率)和MFU(模型浮点计算利用率)。MBU和MFU分别是memory bound和compute bound时所占峰值的比例。MBU和MFU确定了在给定的硬件配置下,还有多少空间可以用于进一步提高推理速度。图2显示了基于TensorRT-LLM的推理服务器在不同张量并行度下测量的MBU。在传输大的连续内存块时,内存带宽利用率达到峰值。类似MPT-7B等较小的模型被分布在多个GPU上时,当每个GPU中移动的内存块较小,相应MBU会更低。

图2:在A100-40G GPU使用TensorRT-LLM时,观察不同张量并行度的MBU。请求:512个输入token的序列,batch size:1。如图3所示,使用NVIDIA H100 GPU观察不同张量并行度和batch size情况下的MBU。MBU随着batch size的增加而减少。然而,随着GPU规模的扩大,MBU的相对下降幅度并没那么明显。另外值得注意的是,选择内存带宽更大的硬件可以使用更少的GPU来提高性能。当batch size为1时,4xA100-40GB GPU对应的MBU为55%,而2xH100- 80GB GPU上可以实现更高的MBU,达到60%(如图2所示)。

图3:在H100-80G GPU上,观察不同batch size和张量并行模式下的MBU。请求:512个输入token的序列。

基准测试结果

延迟

我们测量了MPT-7B和Llama2-70B模型在不同张量并行度下的第一个token生成时间(TTFT)和每个token的生成时间(TPOT)。随着输入提示时间的延长,生成第一个token的时间在总时延中的占比也增加。在多个GPU上实现张量并行有助于减少这种延迟。与模型训练不同的是,扩展到更多GPU对推理延迟的影响是明显递减的。例如,对于Llama2-70B,将GPU从4倍增加到8倍,在batch size较小的情况下,延迟只减少了0.7倍。其中一个原因是并行度越高,MBU越低(如前所述)。另一个原因是张量并行会带来GPU节点间的通信开销。

表1:当输入请求长度为512个token,batch size为1时,生成第一个token的时间。类似Llama2 70B较大的模型,至少需要4xA100-40B GPU才能装入内存。

batch size越大时,张量并行度越高,token延迟相对减少的幅度也就越大。图4显示了MPT-7B每个token输出的时间变化情况。在batch size为1时,GPU从两倍扩展到四倍,token延迟时间减少了约12%。在batch size为16时,4 GPU的延迟比2 GPU低33%。这与我们之前的观察结果一致,即与batch size为1相比,batch size为16时,张量并行度越高,MBU的相对减少幅度越小。

图4:在A100-40GB GPU上扩展MPT-7B时,对每个用户输出每个token所需的时间。延迟并不随着GPU数量的增加而线性增加。请求:128个输入token和64个输出token序列。

图5显示了Llama2-70B的类似结果,只是4 GPU和8 GPU之间的相对提升不太明显。我们还比较了两种不同硬件的GPU缩放情况。由于H100-80GB的GPU内存带宽是A100-40GB的2.15倍,对于4x系统,batch size为1时,延迟降低了36%;batch size为16时,延迟降低了52%。

图5:在多个GPU上扩展Llama-v2-70B时,对每个用户输出每个token所需的时间(输入请求:512个token长度)。注意,这里缺少1x40GB GPU、2x40GB和1x80GB GPU对应的数据,因为Llama-v2-70B(float16)不适合这些系统。

吞吐量

通过batching处理请求,可以权衡吞吐量和每个token所需的时间。与按顺序处理查询相比,在GPU评估期间对查询进行分组可提高吞吐量,但每个查询的完成时间会更长(忽略排队时间)。

以下是几种常见推理请求的批处理方式:

  1. 静态批处理(Static batching):客户端将多个提示打包到请求中,并在batching的所有序列完成后返回响应。我们的推理服务器支持这种方式,但并不要求这样处理。
  2. 动态批处理(Dynamic batching):在服务器内即时批处理提示。通常情况下,这种方法的性能比静态批处理差,但如果响应较短或长度一致,可以接近最佳性能。当请求具有不同参数时,这种方法效果不太好。
  3. 连续批处理(Continuous batching):有论文提出了在请求到达时将其batching在一起,目前是SOTA方法,即不是等待批次中的所有序列都完成,而是在请求到达时将序列以迭代分组在一起。与动态批处理相比,吞吐量可提高10-20倍。

图6:LLM服务的不同批处理类型。批处理是一种提高推理效率的有效方法。

连续批处理通常是共享服务的最佳方法,但在某些情况下,其他两种方法可能更好。在低QPS环境中,动态批处理可能优于连续批处理。有时,在更简单的批处理框架中更容易实现底层GPU优化。对于离线批处理推理工作负载,静态批处理可以避免大量开销,并获得更高的吞吐量。

Batch Size

批处理的效果很大程度上取决于请求流。不过,我们可以通过对统一请求进行静态批处理的基准测试来确定其性能上限。

表2:使用静态批处理和基于FasterTransformers的后端时,MPT-7B的峰值吞吐量(req/sec)。请求:512个输入token和64个输出token。对于较大的输入,OOM边界将位于较小的batch size。

延迟的权衡

请求延迟随batch size的增加而增加。以NVIDIA A100 GPU为例,如果最大吞吐量对应的batch size为64,当batch从1增加到64时,吞吐量提升了14倍,而延时相应地增加了4倍。共享推理服务通常会选择均衡的batch size。自己部署模型的用户应根据自己的应用在延迟和吞吐量之间权衡。在某些应用(如聊天机器人)中,快速响应的低延迟是重中之重。而在其他应用中,比如批量处理非结构化PDF,可能希望牺牲处理单个文档的延迟来快速并行处理所有文档。

图7显示了7B模型的吞吐量与延迟曲线。曲线上的每一条线都是通过将batch size从1增加到256得到的,有助于确定在不同的延迟限制条件下,我们可以使用的batch size。回顾上面的roofline图,可以发现这些策略结果与预期一致。当batch size达到一定规模后,也就是进入compute bound状态,batch size每增加一倍,都只会增加延迟,而不会增加吞吐量。

图7:MPT-7B模型的吞吐量延迟曲线。用户可以在延迟限制条件下选择满足吞吐量要求的硬件配置。使用并行时,了解底层硬件细节非常重要。比如,并非所有云服务商提供的8xA100实例都是相同的。有些服务器在所有GPU之间都是高带宽连接,而有些服务器的GPU是成对的,之间的通信带宽较低。这可能会出现瓶颈,导致实际性能与上述曲线出现明显偏差。

优化案例研究:量化

量化是降低LLM推理硬件要求的常用技术。在推理过程中,降低模型权重和激活的精度可以显著降低硬件要求。例如,在memory bound的环境中,将16 bit权重转换为8 bit权重可以将所需GPU的数量减半(如A100s上的Llama2-70B);将权重降至4 bit,则可以在消费级设备上运行推理(如在Macbook上运行Llama2-70B)。

根据我们的经验,应该谨慎使用量化。原始的量化技术会导致模型质量大幅下降。量化的影响会因模型架构(如MPT与Llama)、大小的不同而不同。

试着使用量化等技术时,我们建议使用像Mosaic Eval Gauntlet这样的LLM质量基准来评估推理系统的质量,而不是评估模型的某个单一指标。此外,探索更深层次的系统优化也很重要。特别是,量化可以使KV缓存更加高效。

如前所述,在token自回归生成过程中,注意力层之前的KV值会被缓存起来,而不用在每一步都重新计算。KV缓存的大小根据每次处理的序列数量和序列长度而变化。此外,在下一次token生成的迭代过程中,新的KV项会被添加到现有的缓存中,使缓存随着新token的生成而增大。

因此,在添加这些新值时,有效的KV缓存内存管理对于良好的推理性能至关重要。Llama2模型使用一类称为分组查询注意力(GQA)的注意变体。注意,当KV头数为1时,GQA与多查询注意力(MQA)相同。GQA通过共享KV值,有助于减少KV缓存。

计算KV缓存大小的公式:batch_size * seqLen * (d_modeL/n_heads) * n_Layers * 2 (K and V) * 2 (bytes per FLoat16) * n_kv_heads

表3显示了在序列长度为1024个token时,按不同batch size计算的GQA KV缓存大小。与70B模型相比,Llama2模型的参数大小是140 GB(Float16)。除了GQA/MQA,量化KV缓存是另一种减少KV缓存大小的方法,我们正在积极评估其对生成质量的影响。

表3:序列长度为1024时Llama-2-70B的KV缓存大小。如前所述,在batch size较小的情况下,LLM生成token是GPU内存带宽受限问题,即生成速度取决于模型参数从GPU内存移动到片上缓存的速度。将模型权重从FP16(2字节)转换为INT8(1字节)或INT4(0.5字节)所需的移动数据更少,因此可以加快token生成速度。但是,量化可能会对模型生成质量产生负面影响。我们目前正在使用Model Gauntlet评估其对模型质量的影响,并计划很快发布相关的后续博文。

结论和主要成果

上述每个因素都会影响构建和部署模型的方式,可以基于硬件类型、软件栈、模型架构以及典型的使用方式,并结合上面的结果来做出数据驱动的决策。以下是根据我们的经验提出的一些建议。

  • 确定优化目标:是关心交互性能吗?最大化吞吐量?还是成本最小化?需要在这些方面进行权衡。
  • 注意延迟的组成部分:对于交互式应用而言,第一个token生成的时间决定了服务的响应速度,而每个输出token的时间则决定了服务的速度。
  • 内存带宽是关键:生成第一个token通常是compute bound,而随后的解码则是memory bound。由于LLM推理经常在memory bound的环境中运行,因此MBU是一个有用的优化指标,可用于比较推理系统的效率。
  • 批处理至关重要:同时处理多个请求对于实现高吞吐量和有效利用昂贵的GPU至关重要。对于共享在线服务来说,连续批处理是必不可少的,而离线批处理推理工作负载可以通过更简单的批处理技术实现高吞吐量。
  • 深度优化:标准的推理优化技术(如算子融合、权重量化)对LLM非常重要,但探索更深层次的系统优化也很重要,尤其是那些能提高内存利用率的优化。KV缓存量化就是一个例子。
  • 硬件配置:应根据模型类型和预期工作量来决定部署的硬件。例如,当扩展到多个GPU时,较小模型(例如MPT-7B)的MBU下降速度比较大模型(LLaMA2-70B)快得多。随着张量并行化程度的提高,性能也会呈亚线性缩放。也就是说,如果流量很高,或者用户愿意为超低的延迟支付溢价,那么对于较小的模型来说,高度的张量并行性仍然是有意义的。
  • 数据驱动决策:虽然理解理论很重要,但我们建议始终测量端到端的服务性能。实现推理部署的性能可能会比预期的差,原因有很多。由于软件效率低下,MBU可能出乎意料地低。或者云提供商之间的硬件差异也可能导致意外(我们观察到两个云提供商的8xA100服务器之间的延迟有2倍的差异)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/556294.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

AI讲师人工智能讲师大模型培训讲师叶梓:突破大型语言模型推理效率的创新方法

大型语言模型(LLM)在自然语言处理(NLP)任务中展现出了前所未有的能力,但它们对计算资源的巨大需求限制了其在资源受限环境中的应用。SparQ Attention算法提出了一种创新的方法,通过减少注意力机制中的内存带…

HBuilder真机调试检测不到荣耀Magic UI系列(包括手机和电脑)解决办法

HBuilder真机调试检测不到荣耀Magic UI系列(包括手机和电脑)解决办法解决方法: 1.在开发人员选项中开启USB调试 如何进入开发者选项? 设置->关于->版本号,点击版本号直至出现您已处于开发者模式 2.选择USB配置…

Github 2024-04-19Java开源项目日报 Top9

根据Github Trendings的统计,今日(2024-04-19统计)共有9个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Java项目9HTML项目1Android开发者实用工具集 创建周期:2820 天开发语言:Java协议类型:Apache License 2.0Star数量:32909 个Fork数量:10631…

北大字节联合发布视觉自动回归建模(VAR):通过下一代预测生成可扩展的图像

北大和字节发布一个新的图像生成框架VAR。首次使GPT风格的AR模型在图像生成上超越了Diffusion transformer。 同时展现出了与大语言模型观察到的类似Scaling laws的规律。在ImageNet 256x256基准上,VAR将FID从18.65大幅提升到1.80,IS从80.4提升到356.4,推理速度提高了20倍。 相…

设计模式——策略模式20

策略模式是一种行为设计模式, 它能让你定义多种算法或行为方式, 并将具体实现放入独立的类中, 以使算法的对象能够相互替换。使用场景例如活动中多种打折策略。 策略抽象 /*** author ggbond* date 2024年04月18日 08:02*/ public interfa…

Linux 系统下的进程间通信 IPC 入门 「中」

以下内容为本人的学习笔记,如需要转载,请声明原文链接 微信公众号「ENG八戒」https://mp.weixin.qq.com/s/39XQUQtGC3Ow-0s0JKWnog 信号量 信号量一般用于配合共享内存的数据传输,共享内存被多个进程之间共享访问,各个进程对共享…

Arcade 用户界面textarea

# 导入所需库 import arcade import arcade.gui# 创建窗口类 class MyWindow(arcade.Window):# 初始化方法def __init__(self):super().__init__(800, 600, "GUI Widgets Example", resizableTrue)# 创建UI管理器,用于处理UI元素self.manager arcade.gui…

2024Mathorcup数学应用挑战赛C题|图神经网络的预测模型+ARIMA时间序列预测模型+人员排班混合整数规划模型|完整代码和论文全解全析

2024Mathorcup数学应用挑战赛C题|图神经网络的预测模型ARIMA时间序列预测模型人员排班混合整数规划模型|完整代码和论文全解全析 我们已经完成了2024Mathorcup数学建模挑战赛C题的40页完整论文和代码,相关内容可见文末,部分图片如下: 问题分…

N元语言模型

第1关:预测句子概率 任务描述 本关任务:利用二元语言模型计算句子的概率 相关知识 为了完成本关任务,你需要掌握:1.条件概率计算方式。 2.二元语言模型相关知识。 条件概率计算公式 条件概率是指事件A在事件B发生的条件下发…

Golang | Leetcode Golang题解之第36题有效的数独

题目: 题解: func isValidSudoku(board [][]byte) bool {var rows, columns [9][9]intvar subboxes [3][3][9]intfor i, row : range board {for j, c : range row {if c . {continue}index : c - 1rows[i][index]columns[j][index]subboxes[i/3][j/3]…

【每日一题】2007. 从双倍数组中还原原数组-2024.4.18

题目: 2007. 从双倍数组中还原原数组 一个整数数组 original 可以转变成一个 双倍 数组 changed ,转变方式为将 original 中每个元素 值乘以 2 加入数组中,然后将所有元素 随机打乱 。 给你一个数组 changed ,如果 change 是 双…

如何获得合适的助听器?

要获得一个合适的助听器,您可以按照以下步骤进行: 1. 咨询专业医生或听力专家:首先,建议您咨询专业的耳鼻喉科医生或听力专家。他们可以通过听力测试来评估您的听力损失程度和类型,并为您提供个性化的建议。 2. 选择信…

DevOps是什么?

DevOps是一系列实践、工具和文化理念的组合,旨在自动化并整合软件开发和信息技术运维团队之间的流程。以下是DevOps的几个关键点: 沟通与协作:DevOps强调开发和运维团队之间的沟通与合作,通过改善这两个部门间的协作关系&#xff…

Labview2024安装包(亲测可用)

目录 一、软件简介 二、软件下载 一、软件简介 LabVIEW是一种由美国国家仪器(NI)公司开发的程序开发环境,它显著区别于其他计算机语言,如C和BASIC。传统的计算机语言是基于文本的语言来产生代码,而LabVIEW则采用图形化…

JavaEE:File类查询一个文件的路径(举例+源码 )

一、File类概述 Java 中通过 java.io.File 类来对一个文件(包括目录)进行抽象的描述。File 类中的方法可以对文件路径以及文件名等信息进行查询,也可以对文件进行各项增删改操作,本文主要介绍 File 类的查询方法。 二、代码示例 …

计算机系统基础知识总结

一、计算机系统概述 计算系统可以分为硬件和软件两部分。硬件主要有中央处理器、存储器、输入和输出设备组成;软件由系统软件和应用软件组成。 冯诺依曼计算机体系:将硬件划分为:输入、输出、运算器、存储器、控制器五部分。 中央处理器&…

【WP】猿人学4 雪碧图、样式干扰

https://match.yuanrenxue.cn/match/4 探索 首先打开Fiddler,发现每个包的除了page参数一样,然后重放攻击可以实现,尝试py复现 Python可以正常拿到数据,这题不考请求,这题的难点原来在于数据的加密,这些数字…

什么是301重定向,什么时候应该使用?301重定向详细说明

如果您将网站从一个URL移动到另一个URL,您需要采取必要的步骤来确保您的访问者被发送到正确的位置。在技术领域,这被称为301重定向。 在这里,我们将讨论什么是301重定向,何时需要使用,以及如何在网站或WordPress中重定…

网络流的C++代码实现与过程讲解

网络流是一种非常重要的图论算法,它在许多实际问题中得到广泛应用。本文将介绍网络流算法的C++代码实现与过程讲解。 算法概述 网络流算法是通过将图中的边看作流量通道,将图的点看作流量的起点或终点,来求解图中的最大或最小流量的问题。它是一种非常重要的最优化算法,广…

闲谈跨部门工作

先附上一张网络流传的IT职场江湖图 然后再来探讨一下在工作中如何跨部门沟通,作为一个团队leader,或者团队的核心开发人员,如何有效的跨部门沟通。 在当今快节奏的软件开发行业中,一个公司的组织架构必然是多样化的,多…