从技术谈到管理,把系统优化的技术用到企业管理

Dify 第 10 篇 Dify 知识库手把手案例 本文介绍了如何利用Dify平台构建《阿里巴巴Java开发手册》智能助手。首先详细讲解了知识库创建的完整流程,包括文档上传、分段设置(推荐父子分段+段落上下文)、索引方式选择(高质量+混合检索)等关键步骤。随后指导用户进行分段质量检查和召回测试,强调TopK和Score参数的调优策略。接着演示了Chatflow应用开发过程,通过知识检索节点和LLM节点的配置,实现从知识库智能获取答案的功能。最后展示了应用发布和实际使用效果,成功实现了基于知识库的问答交互。案例采用DeepSeek-R1大模型,并支持答案引用显 阅读详情

夷称细诔一般而言,代码可分为同步与异步两类。两者同样需要等待操作完成:同步会阻塞当前线程,直至操作结束后再继续执行后续逻辑;异步则不阻塞当前线程,而是在发起操作时预先注册完成后的处理逻辑,待操作完成时由操作本身或外部机制触发该逻辑。

于是这就带来一个问题,那就是同步代码和异步代码的写法是完全不同的!

在 async/await 之前,异步编程通常将回调函数交给异步操作,以便在完成时触发预先编写的逻辑。其后果是:逻辑被拆散到各个回调中,或层层嵌套成“回调地狱”。此外,回调必须由调用方向被调用方传递,迫使调用方提前了解并携带完成后要唤醒的代码,这与自然的思维方式相悖——同一项操作的完成可能会被多个位置同时关心,而发起该操作的代码不应对等待其完成的代码产生任何形式的依赖。

async/await 的出现则从根本上改变了这一点。

async/await#

现如今我们提到 async/await,尽管它仍归入 stackless coroutine 范畴,但已不同于早期那种在递归、错误处理与调用栈追踪上局限颇多的形态;这些局限在很大程度上已经被克服。

.NET 对 async/await 的支持,本质上是编译器对异步方法进行一种 CPS 风格的变换,并将其落地为可恢复的状态机。

举一个具体的例子,当遇到如下代码时:

Copy

async Task Foo()

{

A();

await B();

C();

await E();

F();

}

编译器会以 await 为切分点生成若干“续体”(continuation),并为每个续体捕获所需的局部变量与执行上下文,使其既可被独立调度执行,同时仍能访问 await 之前的状态。这样一来,只需在被等待的操作完成时将下一个续体交给调度器,就可以按自定义策略自由地推进后续代码的执行。异步方法在执行到每一处 await 时会被暂停,等待后续逻辑被重新调度继续执行。因此,await 实际上也标注了异步方法的潜在暂停点。

在 C# 的第一版 async/await 中,这一机制具体抽象为编译期生成的状态机(实现 IAsyncStateMachine),由调度器/同步上下文驱动 MoveNext 逐步推进,从而保证每个代码片段在前一个异步操作完成后被正确调度执行。

然而一直以来 C# 的 async/await 实现都存在一个边界上的问题:C# 编译器以方法为编译单位,既无法跨越方法边界全面洞察被调用方法的实现细节,也不会改变 managed ABI 去擅自修改当前方法的签名。因此,在形成异步调用链时,通常每个 async 方法都会拥有自己的状态机;而在缺乏跨边界全量信息的情况下,调用方会生成较为通用的路径来覆盖异常与暂停等情形。举例来说,即便目标方法在多数情况下并不会抛出异常,调用点仍会保留异常捕获与恢复路径;又或者目标方法很可能不会暂停,调用点也会保留相应的暂停/恢复分支以保证语义正确;又或者比如异步调用链中每一处异步调用都通过 await 对其结果直接进行等待,这种情况下实际上并不需要将异步操作的结果包装进 Task 之类的类型,然而由于需要保持 managed ABI,编译器仍然需要将每一步的结果包装进 Task 里面去;再比如对于实际上没有同步上下文的情况,编译器仍然需要产生备份/恢复同步上下文的代码。

上面的问题使得编译后的 C# 代码难以被 JIT 优化,同时还会产生多余的 Task 对象分配,从而导致 C# 中异步代码的性能一直无法与同步代码相匹敌,甚至出现 ValueTask 这种专门为了消除分配而诞生的类型。

.NET 团队自从 .NET 8 开始尝试对这一现状进行改进。先是对 Green Thread 方案(与 goroutine、Java 的 Virtual Thread 方案相同)进行实验,结果相比目前的 async/await 不仅性能没有提升,反而在跨 runtime 边界调用场景存在不可接受的性能回退和调度问题。在结束这一失败的实验之后,从 .NET 9 开始遍全力向着改进 async/await 本身的方向探索,于是,全新的 Runtime Async 到来了。顺带一提,Runtime Async 最早的名字叫做 Async 2。

Runtime Async#

Runtime Async 下,我们需要编写的 C# 代码不能说没有一点变化,只能说是一点变化没有,只需要用支持 Runtime Async 的新 C# 编译器重新把代码编译一下,代码中的老 Async 代码就会被自动升级为新的 Async 代码,因此并不存在任何的源代码破坏性更改。不过未经重新编译的程序集不会自动升级到新的 Runtime Async 上去。

与依赖 C# 编译器进行 CPS 变换的老 Async 实现相比,新的 Runtime Async 并不需要编译器改写方法体,而是在 runtime 层面引入全新的 async ABI,由运行时直接承载与处理异步控制流。

在 Runtime Async 中,一个方法通过标注 async 这一 attribute(注意不是我们平常使用的 attribute,而是一种直接进入方法签名的特殊 attribute)来表示自己遵循异步方法的 ABI。

比如,假设我们有以下代码:

Copy

async Task Test()

{

await Test();

}

扔给老的 C# 编译器编译则会得到一个状态机;而扔给新的启用了 Runtime Async 支持的 C# 编译器编译,则会得到如下 IL:

Copy

.method public hidebysig

instance class [System.Runtime]System.Threading.Tasks.Task Test() cil managed async

{

ldarg.0

call instance class [System.Runtime]System.Threading.Tasks.Task Program::Test()

call void [System.Runtime]System.Runtime.CompilerServices.AsyncHelpers::Await(class [System.Runtime]System.Threading.Tasks.Task)

ret

}

状态机完全消失了,取而代之的只剩下一个参考实现里面调用了一些 runtime helper 函数,以及我们 IL 代码的方法签名上那一个显著的 async 标记。

以及,我们给方法返回值类型上写的 Task 类型只不过是一个参考,运行的时候 runtime 并不一定会实际为 Task 类型产生代码。并且我们的 C# 代码被编译到 IL 后,IL 代码也只不过是一个参考实现而已,并不是会被真正执行的代码。实际真正被执行的代码则并没有对应的 IL 表示形式,而我们写的这个 C# 函数只不过是要被执行的真实代码的 trunk,或者叫它“启动器”,在异步调用链中实际上并不存在。

在新的异步模型中,当在一个异步方法里等待另一个异步方法时,JIT 会生成暂停逻辑并把当前状态捕获到一个 continuation 对象中;当需要“传递”暂停时,则返回一个非空的 continuation。调用方收到非空 continuation 后,会相应地暂停自身、创建自己的 continuation 并返回。由此形成一条按照调用层次串接起来的 continuation 链式结构。

恢复执行时,通过参数传入一个非空的 continuation,根据其中记录的暂停点(可理解为恢复点标识)跳转到相应位置继续执行;若传入的 continuation 为空,则表示从方法开头开始执行。

你会发现这一实现中,我们付出的额外开销仅仅只有判断 continuation 对象是否是 null 的成本,这简直可以忽略不计!

借助这一机制,runtime 可以在不受 managed ABI 限制的前提下跨越方法进行更积极的全局优化:

被调用的异步方法不会抛异常?异常处理路径删了!

没使用同步上下文?备份/恢复相关逻辑删了!

实际不发生暂停?暂停/恢复分支跳了!

未在后续使用的局部变量?提前结束变量生命周期释放内存!

...

同时,在许多异步等待链中,结果并不需要显式由 Task 进行包装,因此可以在整条链路上彻底消除 Task 抽象:JIT 生成代码时可以直接传递结果本身而非 Task,从而在热路径上实现零分配或接近零分配的效果。除此之外,这还使得 JIT 有能力完全 inline 掉异步方法,从而进一步带来大量的性能提升。

Runtime Async 在大量场景中显著提升了异步代码的性能,使其逼近甚至达到同步代码的性能,并有效降低了分配和内存占用,减少了 GC 压力;同时 Runtime Async 还不会对跨 runtime 边界的互操作与任务调度带来负面影响,可以说成功做到了既要还要。

染色问题?#

当然,每当谈起 async/await 的时候,就会有复读机复读“染色问题”。这种“问题”之所以存在,其实是因为同一套代码需要同时承载同步与异步两种语义。

若完全采用回调式异步,容易导致逻辑分散、可读性下降、维护成本上升,也不太符合直觉;而如果全面协程化(如 goroutine),在异步 runtime 内部通常表现良好,但在跨越 runtime 边界与原生世界交互(如 FFI)时,就会在性能与调度上面临很大的挑战:原生库通常默认以系统线程为边界模型,因此当跨边界调用发生阻塞时,runtime 往往需要避免在同一线程上继续安排其他任务,从而导致额外的开销;同时,由于调度行为与 runtime 紧密耦合,开发者通常较难精确控制代码运行所在的具体系统线程,遇到来自外部的反向回调时也不易回到原先的线程,进而在客户端和游戏等对线程亲和性敏感的场景中水土不服。

async/await 的思路则是“看起来像同步”的方式编写异步,同时让异步走有别于同步的 ABI。它既能保留回调式的性能优势,同时还具备完整的调度灵活性,又有助于降低维护成本。然而主要代价在于需要将结果包装为 Task 等异步类型,这就是人们所说的“染色”,即异步类型沿调用链传播。从抽象上看,可以视作以 Monad 的方式对异步进行建模,从而允许同一异步结果被多方同时等待的同时,还能支持在异步操作结束之后随时访问异步操作的结果。

因此从这一点上来看,async/await 通常能在性能、可维护性与互操作性之间取得较为理想的平衡:书写与调试体验接近同步代码,组合能力(如超时、取消、WhenAll/WhenAny)完善;同时借助 Task 与同步上下文/调度器,在需要时可以对线程亲和性进行更精细的控制,并为跨 FFI 的调用保留清晰的边界。也正因此它在工程实践中被 C++、C#、F#、Rust、Kotlin、JavaScript、Python 等语言广泛采用。

开启方法#

从 .NET 10 RC1 开始,Runtime Async 已经作为实验性预览特性发布了出来,因此想要试用 Runtime Async 的开发者可以抢先体验。

不过需要提前说明的是,现阶段 Runtime Async 仍然处于实验性预览阶段,存在一些 bug,还不适合在实际的生产环境中使用。另外,标准库也还没有采用 Runtime Async 重新进行编译,因此 Runtime Async 只对你自己写的异步代码生效,而调用进标准库里的异步代码后仍然走的是老的 Async 实现。此外,不少优化也还没有实装,因此现阶段的性能表现虽然已经比老的 Async 好了一大截,但离正式版的 Runtime Async 还差了很远。另外虽然计划支持 NativeAOT 但是因为工期不够目前还没有实装。

那么说了这么多,到底如何在 .NET 10 中提前体验 Runtime Async 呢?

首先我们需要修改我们的 C# 项目文件,启用预览功能,并开启 C# 编译器的 Runtime Async 特性支持:

Copy

net10.0

true

$(Features);runtime-async=on

SYSLIB5007

preview

然后我们需要设置环境变量 DOTNET_RuntimeAsync=1 开启 runtime 层面的支持。

这样我们就可以体验 Runtime Async 带来的提升了!

简单测试#

这里我们编写一个递归计算斐波那契数列的方法,但是 async 版本:

Copy

class Program

{

static async Task Main()

{

// 把 Fib 和 FibAsync 预热到 tier 1

for (var i = 0; i < 100; i++)

{

Fib(30);

await FibAsync(30);

await Task.Delay(1);

}

// 进行测试

var sw = Stopwatch.StartNew();

var result = Fib(40);

sw.Stop();

Console.WriteLine($"Fib(40) = {result} in {sw.ElapsedMilliseconds}ms");

sw.Restart();

result = await FibAsync(40);

sw.Stop();

Console.WriteLine($"FibAsync(40) = {result} in {sw.ElapsedMilliseconds}ms");

}

static async Task FibAsync(int n)

{

if (n <= 1) return n;

return await FibAsync(n - 1) + await FibAsync(n - 2);

}

static int Fib(int n)

{

if (n <= 1) return n;

return Fib(n - 1) + Fib(n - 2);

}

}

使用 dotnet run -c Release 运行后得到结果:

Copy

Fib(40) = 102334155 in 250ms

FibAsync(40) = 102334155 in 730ms

而老的 Async 结果长这样:

Copy

FibAsync(40) = 102334155 in 1412ms

可以看到新的 Runtime Async 相比老的 Async 在这一测试上直接成绩暴涨 100%。

其实这还并不是最终我们会看到的成绩。正如前面所说,在 .NET 10 中一部分针对 Runtime Async 的优化其实因为还存在 bug 被临时关闭了。我在这些优化被关闭之前的时候自己编译源码测试过一次 Runtime Async 性能,得到的测试结果如下:

Copy

FibAsync(40) = 102334155 in 255ms

是的你没有看错,在这个测试中异步代码成功做到了和同步代码同样的性能,甚至还是在有这么多层递归的情况之下,以及我们连 ValueTask 都没使用。它相比老的 Async 而言直接提升了接近 500%!

当然,在真实世界的重 I/O 应用场景里,大量的时间其实都消耗在了真实的 I/O 操作本身上,因此总体上并不会有这么夸张的提升。不过对于想要使用 async/await 来做并行计算的同学来说,Runtime Async 可以说是给你们铺平了道路。

结尾#

Runtime Async 作为 .NET 全新的异步方案,在保留源代码兼容性的同时,通过把 async 的实现从编译器搬到 runtime,已经展示出可观的性能改善。对于大规模异步 I/O、链式调用、微服务/云原生等场景,预计将带来更好的延迟与吞吐表现,并减少内存分配与 GC 压力。而在高性能并行计算场景,async/await 也能拥有自己的一席之地。

Python爬虫实战:扒取专利数据库核心信息,我用这招搞定反爬+数据结构化(附完整可运行代码) 这套爬虫方案从「实际需求」出发,解决了专利数据库抓取的核心痛点:反爬突破、数据结构化、标题创作。核心价值不在于代码多复杂,而在于「实用」——我用这套代码半天就抓取了800+条Python爬虫相关专利,比手动效率提升了几十倍。最后想说:爬虫技术的核心是「解决问题」,而不是炫技。专利数据能帮我们快速了解行业技术趋势,尤其是程序员,从专利中扒出的核心逻辑,远比零散的博客文章更系统。希望这篇实战分享能帮到有需要的小伙伴,也欢迎在评论区交流专利爬虫的更多技巧! 阅读详情

相关推荐

【Cadence软件技巧集萃】从Capture到Allergo——分布演示从原理符号导出到网络表

Cadence软件功能多样、性能强大,但是使用起来颇费步骤,尤其是从原理图到网络表的导入步骤,没有经过上手实践还真不一定一次就能搞定哩。本文笔者用将分步演示:1、在Capture软件上绘制原理图;2、将原理图导出网络表;3、在Allergo软件上更新网络表;希望给予使用Cadence的读者有效的帮助1、本文简述了建立Capture项目的步骤,演示了调用元件符号库的方法,并绘制了电气原理图;2、针对加载元件封装库可能遇到的问题,做了排查步骤建议;

qq_33175704的博客 2537

数据时代的的企业管理 记SAP商业同略会

【PConline 资讯】在2012 SAP中国商业同略会城市论坛深圳站上,自SAP中国的萧洁云总裁和张志琦先生,对SAP中国的战略、SAP的技术战略,以及SAP对于行业趋势分析与媒体进行了沟通,对数据时代带给企业的冲击以及企业的应对策略,以及SAP在企业中应用带来的便利与成本节省的案例做出了分享。 2012 SAP中国商业同略会城市论坛深圳站    萧洁云认为数字时代带来的冲击和趋势,以...

weixin_30902251的博客 272

K-Means聚类算法 — 算法原理、质心计算、距离度量、聚类效果评价及优缺点

分类知识   分类是根据样本某些属性或某类特征(可以融合多类特征),把样本类型归为已确定的某一类别中。机器学习中常见的分类算法有:SVM(支持向量机)、KNN(最邻近法)、Decision Tree(决策树分类法)、Naive Bayes(朴素贝叶斯分类)、Neural Networks(神经网络法)等。   但当对海量数据进行分类时,为了降低数据满足分类算法要求所需要的预处理代价,往往需要选...

zhf的博客 1万+

质量管理概述

质量管理概述   技术和管理是国民经济系统中两个相互独立又相互依存的组成部分。技术很重要,管理更重要,“三分技术、七分管理”就是一个形象的说明。质量管理是管理科学中一个重要的分支,随着现代管理科学的发展,现代质量管理也已发展成为一门独立的管理科学——质量管理工程。质量管理的由来与发展   质量管理的产生和发展过程走过了漫长的道路,可以说是源远流长。   人类历史上自有商品生产以来,就开始了以商品的

berson的专栏 1405

An工具介绍之摄像头

An工具介绍之摄像头

人生得意须尽欢 6188

Unity3D赛车游戏+脚本基础

本章主要介绍Unity的基础开发流程以及涉及到的概念。这个过程需要我们学会编写一些游戏脚本,在这讲的过程中我们会完成一个赛车小游戏,因此,在讲述这些基本概念和流程的时候,会同时涉及到一点脚本的开发基础.在游戏,电影和动画中,都有一个渲染的帧率,电影是24帧/s,游戏大概是30帧/s(当然也有60帧/s的)。在unity里面1秒钟,Update方法执行了30次。1秒钟有30帧,帧与帧之所消耗的时间是不一样的,那么我如何知道上一帧用了多少时间?Time.deltaTime就是为了解决这个问题。

m0_58367586的博客 7659

2016驭势科技年终盘点 | 黄波:每一段人生都可以获得不同的成长

今天想聊的话题是,“改变”。以及“改变”随之而来的心理建设。说到底这是一种破除执念,“无我”的能力。佛教中有一个词叫做“我执”,佛法认为“我执”是一切痛苦的根源。虽然这是一个宗教概念,其...

UISEE2031的博客 651

从零搭建 AI 运维 Agent:告警自动诊断 + 修复的完整技术方案

适合读者:管理 5-50 台服务器的运维/SRE 工程师、技术负责人 技术栈:FastAPI + React + PostgreSQL + Redis + DeepSeek 关键词:AI运维、AIOps、自动化运维、智能告警、告警修复、Runbook自动化、DevOps、SRE、DeepSeek运维

weixin_38359457的博客 1640

管理者培养创新能力必读的书籍推荐

而《经理人参阅:创新》没有把创新神秘化,也没有把创新包装成少数天才才能掌握的技能,而是帮助读者建立一套能够在现实工作中持续应用的创新思维框架。市场环境在变化,客户需求在变化,技术也在不断迭代,如果组织的思维方式始终停留在过去,那么所谓的经验最终可能变成发展的障碍。然而在实际工作中,无论是企业经营、团队管理、市场营销还是产品开发,创新早已不再是少数人的专利,而是一种必须掌握的核心能力。而《经理人参阅:创新》所传递的,正是如何从管理层面构建创新机制,让创新不再依赖个人英雄主义,而成为组织能力的一部分。

Anthony的专栏 87

3.4 ISIS和OSPF之间路由引入

通过以上输出可以看到OSPF的路由引入到了IS-IS中。通过以上输出可以看到ISIS的路由没有传递给OSPF。通过以上输出可以看到OSPF的路由没有传递给ISIS。通过以上输出可以看到ISIS的路由被引入进了OSPF。掌握在IS-IS中引入OSPF路由的方法。掌握在OSPF中引入IS-IS路由的方法。图3-3:ISIS和OSPF之间路由引入。在R3上把ISIS的路由引入到OSPF。OSPF引入外部路由的缺省度量值为1。在R3上把OSPF的路由引入到ISIS。引入的外部路由类型为Type2。

lwljh134的博客 1803

【全志V821_FoxPi】6-3 GC2083 MIPI摄像头适配

本文介绍了在全志V821芯片上适配GC2083 MIPI摄像头的方案。GC2083是一款支持1080P@30fps的高性能CMOS图像传感器,采用MIPI CSI-2接口,具有低功耗特性。文章详细列出了传感器的技术参数和工作电压要求,并提供了设备树配置示例,包括CSI接口、ISP处理单元和传感器节点的具体设置。通过快速配置命令one_gc2083_sensor或手动修改设备树即可启用该摄像头模组,适用于IPC等对图像质量有要求的嵌入式应用场景。

第四维度的博客 1928

ERP合身,才是最好的

  康特尔接触ERP最早是在2005年,由公司自己组建的团队开发了一套进销存系统使用。随着公司迅速的壮大和上市管理的需要,康特尔决定应该选择专业的ERP公司合作,进行信息化的管理,随后他们便开始选型。  谈到选型,康特尔电子有限公司资讯部经理张永东表示,对于完全没有ERP实施经验的人来说,选型是一个非常令人头痛的过程。  张永东透露,选型之初,康特尔对国内外多家ERP企业,其中不乏SAP等

尚阳的专栏 3063

Apollo 9.0 速度非线性规划算法 – piecewise jerk speed nonlinear optimizer Ⅰ

二次规划的速度规划算法(PiecewiseJerkSpeedOptimizer)的存在两个问题: 这里以一张图来说明上面的问题,假设存在一个实际限速区间(或曲率很大需要降速的区间)[S1, S2],PiecewiseJerkSpeedOptimizer的做法是根据动态规划的st曲线(黑色),找到具体的时间区间[T1, T2],然后对区间[T1, T2]内所有的点施加约束或惩罚。但是二次规划平滑后的曲线(黄色)发生了变化,那么限速区间[S1, S2]对应的时间区间[T1, T2]也发生了变化,所以实际应该是对

WaiNgai 334

大数据的核心价值

随着互联网的高速发展,信息的传输越来越方便快捷,人工智能、区块链等高科技在内的前沿技术都让我们的生活越来越便利,在这样的时代里,每个人都将成为越来越透明的存在,因为足够了解,所以才能够提供足够的便利。而这一切,正是大数据所催生。数据已经被认为是继云计算、物联网之后颠覆性的一次技术性革命。 随着社会不断发展的脚步,各类数据不断累积,如果说小数据时代的各类分析调研更多的是靠样本采集,那么现在,不管从

Seriously_1的博客 2748

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

ubuntu桌面之路-续四

4,应用优化。卸载掉系统自带的游戏和一切华而不实的管理应用;干掉雷鸟(我的网易企业邮死活安装不上,重装系统几遍都无济于事),安装Evolution;干掉Libreoffice ,安装WPS;其实都用得不多,只是不想远程桌面的时候,方便取用,更多的是用来装下13而已。说实话,Evolution给我一种很惊艳的感觉,功能和界面不输给windows下foxmail.这些在Ubunt...

weixin_34214500的博客 210

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

上一篇: 如何快速无缝的从 vscode 转向AI编辑器 cursor、kiro、trae 等
下一篇: 验证码对抗之路及现有验证机制介绍
普通网友
博客等级 码龄1年 2粉丝 77原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值