展开菜单
首页 精品内容 本月促销 装机必备 Windows PDF教程 macOS软件 IOS软件 Android AI 专题
全部分类

当前位置:

首页 > 编程开发 > 如何反向绘制出 .NET程序 异步方法调用栈(最新)

如何反向绘制出 .NET程序 异步方法调用栈(最新)

一:背景1. 讲故事这个问题源于给训练营里一位朋友分析卡死dump时遇到的情况。当时需要在分析期间拿到某一个异步方法的调用栈,但程序跑在 .NET Framework 4.8 上,SOS 后续版本才有的 !dumpasync 命令用不了,这就有点尴尬了。不过转念一想,既然 !dumpasync 能把

本文目录

    一:背景

    1. 讲故事

    这个问题源于给训练营里一位朋友分析卡死dump时遇到的情况。当时需要在分析期间拿到某一个异步方法的调用栈,但程序跑在 .NET Framework 4.8 上,SOS 后续版本才有的 !dumpasync 命令用不了,这就有点尴尬了。不过转念一想,既然 !dumpasync 能把调用栈搞出来,理论上手动也能把它捞出来,于是就有了这篇内容。

    二:异步调用栈研究

    1. 一个简单的案例

    为了模拟得更真实一点,搞一个简单的三层架构,最后在 DAL 层的 ReadAsync 之后给它断住,参考代码如下:

    namespace Example_18_1_1.UI{    internal class Program    {        static void Main(string[] args)        {            Task.Run(() =>            {                var task = GetCustomersAsync();                Console.WriteLine(task.IsCompleted);            });            Console.ReadLine();        }        static async Task GetCustomersAsync()        {            string connectionString = @"Server=(localdb)\MyInstance;Database=MyDatabase;Integrated Security=true;";            try            {                Console.WriteLine("Starting async database query...");                // 初始化服务                var customerService = new CustomerService(connectionString);                // 获取并显示客户数据                var customers = await customerService.GetCustomersForDisplayAsync();                foreach (var customer in customers)                {                    Console.WriteLine($"Customer: ID={customer.Id}, Name={customer.Name}");                }                Console.WriteLine("Query completed successfully.");            }            catch (Exception ex)            {                Console.WriteLine($"Error: {ex.Message}");            }        }    }}namespace Example_18_1_1.BLL{    public class CustomerService    {        private readonly CustomerRepository _repository;        public CustomerService(string connectionString)        {            _repository = new CustomerRepository(connectionString);        }        public async Task> GetCustomersForDisplayAsync()        {            // 这里可以添加业务逻辑,如验证、转换等            var customers = await _repository.GetTop10CustomersAsync();            // 示例业务逻辑:确保名称不为null            foreach (var customer in customers)            {                customer.Name ??= "Unknown";            }            return customers;        }    }}namespace Example_18_1_1.DAL{    public class CustomerRepository    {        private readonly string _connectionString;        public CustomerRepository(string _connectionString)        {            _connectionString = _connectionString;        }        public async Task> GetTop10CustomersAsync()        {            var customers = new List();            await using (var connection = new SqlConnection(_connectionString))            {                await connection.OpenAsync();                var command = new SqlCommand("SELECT TOP 10 * FROM Customers", connection);                await using (var reader = await command.ExecuteReaderAsync())                {                    while (await reader.ReadAsync())                    {                        customers.Add(new Customer                        {                            Id = Convert.ToInt32(reader["Id"]),                            Name = Convert.ToString(reader["Name"])                        });                        Debugger.Break();                    }                }            }            return customers;        }    }    public class Customer    {        public int Id { get; set; }        public string Name { get; set; }    }}

    从代码流程看,异步调用链是这样的:GetCustomersAsync -> GetCustomersForDisplayAsync -> GetTop10CustomersAsync。程序中断之后,用 WinDbg 附加,使用 !clrstack 观察当前调用栈。

    0:017> !clrstackOS Thread Id: 0x3118 (17)        Child SP               IP Call Site000000ABD6CBEAF8 00007ffeb1e61db2 [HelperMethodFrame: 000000abd6cbeaf8] System.Diagnostics.Debugger.BreakInternal()000000ABD6CBEC00 00007ffdf818a91a System.Diagnostics.Debugger.Break() [/_/src/coreclr/System.Private.CoreLib/src/System/Diagnostics/Debugger.cs @ 18]000000ABD6CBEC30 00007ffd9915079d Example_18_1_1.DAL.CustomerRepository+d__2.MoveNext() [D:\skyfly\18.20220727\src\Example\Example_18_1_1\Program.cs @ 115]000000ABD6CBEE50 00007ffdf827f455 System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1[[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib]].ExecutionContextCallback(System.Object) [/_/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncTaskMethodBuilderT.cs @ 286]000000ABD6CBEE80 00007ffdf808dde9 System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object) [/_/src/libraries/System.Private.CoreLib/src/System/Threading/ExecutionContext.cs @ 183]000000ABD6CBEEF0 00007ffdf827f593 System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1[[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib]].MoveNext(System.Threading.Thread) [/_/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncTaskMethodBuilderT.cs @ 324]000000ABD6CBEF60 00007ffdf827f4ec System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1[[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib]].MoveNext() [/_/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncTaskMethodBuilderT.cs @ 302]000000ABD6CBEF90 00007ffdf80a9a06 System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(System.Runtime.CompilerServices.IAsyncStateMachineBox, Boolean) [/_/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/TaskContinuation.cs @ 795]000000ABD6CBEFF0 00007ffdf80a48eb System.Threading.Tasks.Task.RunContinuations(System.Object) [/_/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs @ 3374]000000ABD6CBF0D0 00007ffdf80a4866 System.Threading.Tasks.Task.FinishContinuations() [/_/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs @ 3350]000000ABD6CBF110 00007ffdf8251350 System.Threading.Tasks.Task`1[[System.__Canon, System.Private.CoreLib]].TrySetResult(System.__Canon) [/_/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Future.cs @ 400]000000ABD6CBF160 00007ffdf8254fc3 System.Threading.Tasks.UnwrapPromise`1[[System.__Canon, System.Private.CoreLib]].TrySetFromTask(System.Threading.Tasks.Task, Boolean)000000ABD6CBF1C0 00007ffdf825515b System.Threading.Tasks.UnwrapPromise`1[[System.__Canon, System.Private.CoreLib]].ProcessInnerTask(System.Threading.Tasks.Task) [/_/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs @ 6940]000000ABD6CBF200 00007ffdf8254ead System.Threading.Tasks.UnwrapPromise`1[[System.__Canon, System.Private.CoreLib]].ProcessCompletedOuterTask(System.Threading.Tasks.Task)000000ABD6CBF240 00007ffdf8254d1b System.Threading.Tasks.UnwrapPromise`1[[System.__Canon, System.Private.CoreLib]].Invoke(System.Threading.Tasks.Task) [/_/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs @ 6802]000000ABD6CBF280 00007ffdf80a4e11 System.Threading.Tasks.Task.RunOrQueueCompletionAction(System.Threading.Tasks.ITaskCompletionAction, Boolean)000000ABD6CBF2C0 00007ffdf80a4c0a System.Threading.Tasks.Task.RunContinuations(System.Object) [/_/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs @ 3392]000000ABD6CBF3A0 00007ffdf80a4866 System.Threading.Tasks.Task.FinishContinuations() [/_/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs @ 3350]000000ABD6CBF3E0 00007ffdf80a2e9f System.Threading.Tasks.Task.FinishStageThree() [/_/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs @ 2125]000000ABD6CBF410 00007ffdf80a2d0b System.Threading.Tasks.Task.FinishStageTwo() [/_/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs @ 2095]000000ABD6CBF460 00007ffdf80a33f6 System.Threading.Tasks.Task.ExecuteWithThreadLocal(System.Threading.Tasks.Task ByRef, System.Threading.Thread) [/_/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs @ 2350]000000ABD6CBF500 00007ffdf80a3293 System.Threading.Tasks.Task.ExecuteEntryUnsafe(System.Threading.Thread) [/_/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs @ 2271]000000ABD6CBF540 00007ffdf80a323a System.Threading.Tasks.Task.ExecuteFromThreadPool(System.Threading.Thread) [/_/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs @ 2262]000000ABD6CBF570 00007ffdf80969df System.Threading.ThreadPoolWorkQueue.Dispatch()000000ABD6CBF610 00007ffdf809e566 System.Threading.PortableThreadPool+WorkerThread.WorkerThreadStart() [/_/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.WorkerThread.cs @ 107]000000ABD6CBF730 00007ffdf8082f0f System.Threading.Thread.StartCallback() [/_/src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs @ 105]000000ABD6CBF9C0 00007ffdf8ccbde3 [DebuggerU2MCatchHandlerFrame: 000000abd6cbf9c0] 

    卦中真的是眼花缭乱,找瞎了眼也没找到调用链上的三个方法名,只有一个 Example_18_1_1.DAL.CustomerRepository+d__2 状态机类,经过 ILSpy 反编译才能勉强看到是 GetTop10CustomersAsync 方法,截图如下:

    如何反向绘制出 .NET程序 异步方法调用栈(最新)

    所以 SOS 为了让调试者免去这个痛苦,新增了 !dumpasync 命令。

    0:017> !dumpasyncSTACK 10000028b00029338 00007ffd993d1e00 (-1) Example_18_1_1.DAL.CustomerRepository+d__2 @ 7ffd991502a0  0000028b00029438 00007ffd993d3290 (0) Example_18_1_1.BLL.CustomerService+d__2 @ 7ffd9914d6c0    0000028b00029550 00007ffd993d3fe8 (0) Example_18_1_1.UI.Program+d__1 @ 7ffd9914b8f0

    虽然能以屏蔽外部代码的方式显示异步调用栈,但这个 SOS 命令是 .NET Core 独有的。作为高级调试者,必须掌握手工绘制的能力。

    2. 如何手工绘制

    要想手工绘制,需要了解异步状态机的内部机制——子函数和父函数是通过 m_continuationObject 字段串联的。关于异步方法串联的底层机制,之前有过专门讨论,这里不再赘述,用一张图来表示吧。

    如何反向绘制出 .NET程序 异步方法调用栈(最新)

    本质上来说,就是 Box 之间形成了一个跨线程的由 m_continuationObject 串联出的单链表。有了思路之后,开始验证。使用 !dso 找到头节点 box。

    0:017> !dsoOS Thread Id: 0x3118 (17)          SP/REG           Object Name             rbx     028b00029338 System.Runtime.CompilerServices.AsyncTaskMethodBuilder>+AsyncStateMachineBoxd__2>....0:017> !dumpobj /d 28b00029338Name:        System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1[[System.Collections.Generic.IEnumerable`1[[Example_18_1_1.DAL.Customer, Example_18_1_1]], System.Private.CoreLib],[Example_18_1_1.DAL.CustomerRepository+d__2, Example_18_1_1]]Fields:              MT    Field   Offset                 Type VT     Attr            Value Name...00007ffd99125690  4000db9       20        System.Object  0 instance 0000028b00029438 m_continuationObject...0:017> !DumpObj /d 0000028b00029438Name:        System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1[[System.Collections.Generic.IEnumerable`1[[Example_18_1_1.DAL.Customer, Example_18_1_1]], System.Private.CoreLib],[Example_18_1_1.BLL.CustomerService+d__2, Example_18_1_1]]Fields:              MT    Field   Offset                 Type VT     Attr            Value Name...00007ffd99125690  4000db9       20        System.Object  0 instance 0000028b00029550 m_continuationObject...0:017> !DumpObj /d 0000028b00029550Name:        System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1[[System.Threading.Tasks.VoidTaskResult, System.Private.CoreLib],[Example_18_1_1.UI.Program+d__1, Example_18_1_1]]Fields:              MT    Field   Offset                 Type VT     Attr            Value Name...00007ffd99125690  4000db9       20        System.Object  0 instance 0000000000000000 m_continuationObject...00007ffd99125708  4001337       48       System.__Canon  0 instance 0000028b0000e7f8 StateMachine...

    上面三个 m_continuationObject 值正是 !dumpasync 输出的结果。最后一个 m_continuationObject=null 说明是异步执行流的最后一个节点,流程正在这里没出来。可以把这个异步状态机解包出来,即卦中的 StateMachine 字段,输出如下:

    0:017> !do 0000028b0000e7f8Name:        Example_18_1_1.BLL.CustomerService+d__2Fields:              MT    Field   Offset                 Type VT     Attr            Value Name00007ffd991c94b0  4000018       30         System.Int32  1 instance                0 <>1__state00007ffd9924fca0  4000019       38 ...Private.CoreLib]]  1 instance 0000028b0000e830 <>t__builder00007ffd99247298  400001a        8 ...L.CustomerService  0 instance 0000028b0000e7c8 <>4__this00007ffd992453b0  400001b       10 ... Example_18_1_1]]  0 instance 0000000000000000 5__100007ffd992453b0  400001c       18 ... Example_18_1_1]]  0 instance 0000000000000000 <>s__200007ffd99246d60  400001d       20 ... Example_18_1_1]]  0 instance 0000000000000000 <>s__300007ffd99245338  400001e       28 ..._1_1.DAL.Customer  0 instance 0000000000000000 5__400007ffd99245448  400001f       40 ...Private.CoreLib]]  1 instance 0000028b0000e838 <>u__1

    再配上 ILSpy 反编译出来的状态机代码,截图如下:

    如何反向绘制出 .NET程序 异步方法调用栈(最新)

    可以根据这里的字段赋值情况来推测当前正执行哪一个阶段。

    3. 父节点如何找到子节点

    刚才我们是通过 子节点 -> 父节点 寻找法。在真实的 dump 分析中,可能还会存在反向的情况,即 父节点 -> 子节点 寻找法。但父节点在寻找目标子节点的过程中会存在多条链路,比如 GetTop10CustomersAsync 方法中存在五个 await 就对应着 4 条链路。

    如何反向绘制出 .NET程序 异步方法调用栈(最新)

    用状态机的话术就是下面的 4 个 <>u__xxxx。

    如何反向绘制出 .NET程序 异步方法调用栈(最新)

    可能有些朋友还是有点懵,没关系,再绘制一张图。

    如何反向绘制出 .NET程序 异步方法调用栈(最新)

    最后通过 Windbg 来验证一下。

    0:017> !do 0000028b00029550 Name:        System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1[[System.Threading.Tasks.VoidTaskResult, System.Private.CoreLib],[Example_18_1_1.UI.Program+d__1, Example_18_1_1]]Fields:              MT    Field   Offset                 Type VT     Attr            Value Name00007ffd99125708  4001337       48       System.__Canon  0 instance 0000028b0000de10 StateMachine0:017> !DumpObj /d 0000028b0000de10Name:        Example_18_1_1.UI.Program+d__1Fields:              MT    Field   Offset                 Type VT     Attr            Value Name00007ffd99245448  400002b       50 ...Private.CoreLib]]  1 instance 0000028b0000de60 <>u__10:017> !DumpVC /d 00007ffd99245448 0000028b0000de60Name:        System.Runtime.CompilerServices.TaskAwaiter`1[[System.Collections.Generic.IEnumerable`1[[Example_18_1_1.DAL.Customer, Example_18_1_1]], System.Private.CoreLib]]Fields:              MT    Field   Offset                 Type VT     Attr            Value Name00007ffd99247db8  400139e        0 ...Private.CoreLib]]  0 instance 0000028b00029438 m_task0:017> !DumpObj /d 0000028b00029438Name:        System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1[[System.Collections.Generic.IEnumerable`1[[Example_18_1_1.DAL.Customer, Example_18_1_1]], System.Private.CoreLib],[Example_18_1_1.BLL.CustomerService+d__2, Example_18_1_1]]Fields:              MT    Field   Offset                 Type VT     Attr            Value Name00007ffd99125708  4001337       48       System.__Canon  0 instance 0000028b0000e7f8 StateMachine0:017> !DumpObj /d 0000028b0000e7f8Name:        Example_18_1_1.BLL.CustomerService+d__200007ffd99245448  400001f       40 ...Private.CoreLib]]  1 instance 0000028b0000e838 <>u__10:017> !DumpVC /d 00007ffd99245448 0000028b0000e838Name:        System.Runtime.CompilerServices.TaskAwaiter`1[[System.Collections.Generic.IEnumerable`1[[Example_18_1_1.DAL.Customer, Example_18_1_1]], System.Private.CoreLib]]Fields:              MT    Field   Offset                 Type VT     Attr            Value Name00007ffd99247db8  400139e        0 ...Private.CoreLib]]  0 instance 0000028b00029338 m_task0:017> !DumpObj /d 0000028b00029338Name:        System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1[[System.Collections.Generic.IEnumerable`1[[Example_18_1_1.DAL.Customer, Example_18_1_1]], System.Private.CoreLib],[Example_18_1_1.DAL.CustomerRepository+d__2, Example_18_1_1]]MethodTable: 00007ffd993d1e00EEClass:     00007ffd993c1810Tracked Type: falseSize:        96(0x60) bytesFile:        C:\Program Files\dotnet\shared\Microsoft.NETCore.App\6.0.36\System.Private.CoreLib.dllFields:              MT    Field   Offset                 Type VT     Attr            Value Name00007ffd99125708  4001337       48       System.__Canon  0 instance 0000028b0000e870 StateMachine0:017> !DumpObj /d 0000028b0000e870Name:        Example_18_1_1.DAL.CustomerRepository+d__2Fields:              MT    Field   Offset                 Type VT     Attr            Value Name...00007ffd992602f0  4000014       60 ...vices.TaskAwaiter  1 instance 0000028b0000e8d0 <>u__100007ffd99267a60  4000015       68 ....Data.SqlClient]]  1 instance 0000028b0000e8d8 <>u__200007ffd99260450  4000016       70 ...Private.CoreLib]]  1 instance 0000028b0000e8e0 <>u__300007ffd99260ae8  4000017       78 ....ValueTaskAwaiter  1 instance 0000028b0000e8e8 <>u__4

    4. 有没有更快捷的方式

    手工绘制虽然是兜底方案,但每次都要这样搞也确实太累。最近在思考有没有更好的方式,好巧不巧,昨天在知乎上刷到了这样一篇文章,hez2010 大佬的一句话点醒了我,截图如下:

    如何反向绘制出 .NET程序 异步方法调用栈(最新)

    点醒的是什么呢?SOS 解析托管代码的能力远不如官方的 Visual Studio,毕竟后者才是全球最专业的托管代码调试器。将生成好的 dump 丢到 VS 中,在 Stack 或者 Parallel Stack 中一定要屏蔽 外部代码(External Code),否则海量的 AsyncTaskMethodBuilder 和 MoveNext 会淹死我们,截图如下:

    如何反向绘制出 .NET程序 异步方法调用栈(最新)

    三:总结

    手工绘制异步调用栈需要对异步的底层构建有一个清晰的认识,调试师是痛苦的。要想进阶为资深,需要日积月累的底层知识沉淀。在自我学习的过程中,如果没有无数次“在绝望中寻找希望”的能力,很容易从入门到放弃……

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发
    相关文章 更多
    精品专题 更多
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    macOS软件

    正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

    IOS软件

    正软商城iOS软件专区,精选适用于iPhone和iPad的办公、学习、影音、设计、效率及AI应用,提供功能介绍、适用设备、系统要求和正版获取方式等信息。

    AI

    正软商城AI软件专区,汇集AI写作、AI绘画、AI视频、AI办公、AI编程、AI翻译、智能客服和数据分析等人工智能工具,提供功能介绍、适用平台、收费方式及正版购买信息。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    立刻MV 网页版
    立刻MV 网页版

    立刻MV 面向音乐人、内容创作者和品牌团队,帮助用户低成本完成歌曲 MV、歌词视频、AI 分镜、图生视频与最终合成。

    蛙蛙写作 网页版
    蛙蛙写作 网页版

    蛙蛙写作 AI 创作工具,覆盖小说、剧本、文案,一键生成文稿,打通文字转视频全流程,高效解决创作难题。

    超级简历WonderCV 网页版
    超级简历WonderCV 网页版

    超级简历WonderCV是面向应届生和AI小白的智能求职平台,覆盖简历、面试与职业规划。

    音述AI 网页版
    音述AI 网页版

    音述AI,是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区。

    AionClaw macOS版
    AionClaw macOS版

    AionClaw 是可在桌面端运行的任务型 AI 助手,通过数字专家与技能市场组合办公、创作、数据和开发能力。

    Loomy macOS版
    Loomy macOS版

    Loomy 是科大讯飞推出的桌面 AI 助手,可通过对话、任务与工作目录协助处理办公、内容创作和资料整理。

    AirBuddy 3 macOS版
    AirBuddy 3 macOS版

    AirBuddy 3 是面向 macOS 的蓝牙外设增强工具,可集中查看 AirPods、Beats 与苹果设备电量,提供快速连接、播放控制、电量提醒、桌面小组件和多台 Mac 外设接力等功能。

    AirServer macOS版
    AirServer macOS版

    AirServer macOS版可把 Mac 转换为无线投屏接收端,通过 AirPlay 或 Google Cast 接收手机、平板和电脑画面,并支持多设备同时连接、高清镜像及会话录制,适合家庭娱乐、课堂教学、会议演示和应用展示。

    AnyDesk macOS版
    AnyDesk macOS版

    AnyDesk macOS版是一款适用于远程办公、设备维护和客户支持的远程桌面工具,可连接并操作异地计算机,支持文件传输、无人值守访问、会话权限控制及跨平台协作。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。

    讯飞绘文 网页版
    讯飞绘文 网页版

    讯飞绘文网页版是科大讯飞推出的AI图文创作与内容运营工具,覆盖热点选题、文章生成、稿件校对、智能配图、排版发布和数据复盘等环节,适合自媒体创作者及内容团队在线使用。

    Maya(Autodesk Maya) Windows版
    Maya(Autodesk Maya) Windows版

    Autodesk Maya 是面向影视、电视、动画和游戏行业的专业三维制作软件,集多边形与 NURBS 建模、角色绑定、关键帧和动作捕捉动画、Bifrost 特效模拟、材质开发及 Arnold 渲染于一体,

    Aperty Windows版
    Aperty Windows版

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    立刻MV 网页版
    立刻MV 网页版

    立刻MV 面向音乐人、内容创作者和品牌团队,帮助用户低成本完成歌曲 MV、歌词视频、AI 分镜、图生视频与最终合成。

    蛙蛙写作 网页版
    蛙蛙写作 网页版

    蛙蛙写作 AI 创作工具,覆盖小说、剧本、文案,一键生成文稿,打通文字转视频全流程,高效解决创作难题。

    超级简历WonderCV 网页版
    超级简历WonderCV 网页版

    超级简历WonderCV是面向应届生和AI小白的智能求职平台,覆盖简历、面试与职业规划。

    音述AI 网页版
    音述AI 网页版

    音述AI,是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区。

    AionClaw Windows版
    AionClaw Windows版

    AionClaw 是可在桌面端运行的任务型 AI 助手,通过数字专家与技能市场组合办公、创作、数据和开发能力。

    Loomy Windows版
    Loomy Windows版

    Loomy 是科大讯飞推出的桌面 AI 助手,可通过对话、任务与工作目录协助处理办公、内容创作和资料整理。