C++异步编程入门:用std::async轻松实现后台任务

发布时间:2026/7/21 14:07:28

C++异步编程入门:用std::async轻松实现后台任务
你是不是觉得C异步编程听起来就头大线程、锁、回调、future/promise……网上的教程要么上来就讲std::async和std::future要么直接深入线程池和任务队列对新手极不友好。很多C开发者因此对异步望而却步宁愿写低效的同步代码或者用其他语言来规避这个问题。但异步编程的核心思想其实很简单让耗时的操作在后台进行不阻塞主线程从而提高程序的响应能力和吞吐量。在C11之后标准库已经为我们提供了足够简单、安全的工具来入门异步编程根本不需要一开始就面对复杂的并发模型。这篇文章要解决的问题很明确用最直观的方式带你绕过那些复杂的概念直接上手写出第一个可运行的C异步程序。我们不谈高深的无锁队列也不设计复杂的线程池就从你手头可能正在写的、一个会“卡住”界面的同步函数开始用标准库提供的最简单工具把它改造成异步版本。你会发现入门C异步真的只需要理解几个关键概念和几行代码。读完本文你将能清晰地回答我的程序哪里需要异步用C标准库实现异步的最短路径是什么写出来的代码如何调试和排查常见问题1. 为什么你的C程序需要异步在深入代码之前我们必须先达成一个共识不是所有程序都需要异步。滥用异步只会增加代码的复杂度和调试难度。那么什么情况下你应该考虑使用异步呢想象以下几个真实场景图形界面GUI应用你点击一个“加载大文件”的按钮整个界面冻结、失去响应直到文件加载完成。用户体验极差。这就是典型的需要将耗时I/O操作异步化的场景。网络服务器一个简单的同步服务器在处理一个客户端的慢速请求时其他所有客户端都必须等待。这严重限制了服务器的并发能力。计算密集型任务你的程序需要进行大量的数据计算如图像处理、物理模拟如果计算在主线程进行程序就无法处理任何其他输入或更新界面。需要同时等待多个事件例如程序需要同时监听网络套接字、用户输入和定时器。用同步轮询的方式会浪费CPU而用多线程分别阻塞又过于笨重。异步模型如I/O多路复用是更优雅的解决方案。核心判断当你的程序中存在可能阻塞主执行流的耗时操作I/O等待、复杂计算、睡眠等并且你希望在这些操作进行时程序还能做其他有用的事情如响应用户、处理其他请求这时就该引入异步。对于C开发者好消息是C11标准引入的头文件提供了std::async和std::future这一对“黄金搭档”它屏蔽了底层线程管理的复杂性让你能以近乎同步的思维模式来写异步代码。这是你踏入C异步世界最平滑的入口。2. 理解核心概念异步、Future与Promise在开始写代码前我们需要统一三个关键术语。别怕它们比你想象的要简单。异步Asynchronous指操作的发起和完成是分离的。你发出一个“去做某件事”的指令后不必原地等待它完成可以立刻继续执行后面的代码。就像你在网上下单购物发起操作然后可以去工作或娱乐继续执行等快递到了再处理处理结果。Future可以理解为一张“提货单”或“欠条”。当你启动一个异步任务时它会立即返回一个future对象。这个future代表了一个“在未来某个时刻才会有的值”。你现在拿不到结果但凭这张“欠条”你可以在之后需要的时候去“提取”结果。Promise这是future的另一半是结果的“生产者”或“承诺者”。异步任务在后台运行计算完成后将结果“放入”对应的promise中。一旦结果被放入与之关联的future就“就绪”了可以取出值。在std::async这个高层接口中promise被隐藏了起来我们直接和future打交道。一个生动的类比 你去咖啡店点一杯现磨手冲咖啡。同步你点单后就站在柜台前死死盯着咖啡师做完每一步直到拿到咖啡才离开。期间你不能做任何其他事如回工作消息。异步你点单后咖啡师给你一个取餐号Future。你可以立刻离开柜台去找个座位处理工作消息继续执行主线程。咖啡师异步任务在后厨制作咖啡这是他的Promise。咖啡做好后叫你的号你凭取餐号去取结果。std::async就是那个帮你生成取餐号future并安排咖啡师启动异步任务的店长。3. 环境准备现代C编译器本文的代码基于C11及以上标准。这是使用std::async和std::future的最低要求。请确保你的开发环境支持C11。GCC: 版本 4.8.1 (使用编译选项-stdc11)Clang: 版本 3.3MSVC (Visual Studio): Visual Studio 2015 及以上版本检查你的编译器版本# 对于 GCC g --version # 编译时指定标准 g -stdc11 -o my_async_app my_async_app.cpp # 对于 Clang clang --version # 对于 MSVC在Visual Studio项目中将“C语言标准”设置为“ISO C11 Standard”或更高。一个简单的测试程序创建一个名为test_cpp11.cpp的文件。#include iostream #include thread int main() { std::cout C标准版本: __cplusplus std::endl; std::cout 支持std::thread说明至少是C11 std::endl; return 0; }编译并运行如果__cplusplus输出201103或更大的值并且能正常使用std::thread则环境准备就绪。4. 从同步到异步一个完整的代码改造示例让我们从一个会导致界面“卡死”的同步程序开始一步步将它改造成异步版本。4.1 问题程序同步的耗时任务假设我们有一个模拟“处理用户上传的大文件”的函数它需要3秒钟。在GUI中调用这个函数会阻塞事件循环3秒。// sync_problem.cpp #include iostream #include chrono #include thread // 模拟一个耗时的任务比如处理文件 void processBigFile(const std::string filename) { std::cout [开始] 处理文件: filename std::endl; // 模拟耗时操作睡眠3秒 std::this_thread::sleep_for(std::chrono::seconds(3)); std::cout [完成] 文件 filename 处理完毕 std::endl; } int main() { std::cout 主线程用户点击了‘处理文件’按钮。 std::endl; // 同步调用这里会阻塞主线程3秒 processBigFile(user_data.zip); // 下面的代码必须等上面的函数执行完才能运行 std::cout 主线程文件处理中界面被冻结...实际上你看不到这条消息因为被阻塞了 std::endl; std::cout 主线程现在可以更新UI进度条或响应用户其他点击了。 std::endl; return 0; }运行这个程序你会发现输出是顺序的并且中间有3秒的停顿。在GUI中这3秒内整个窗口会无法操作。4.2 解决方案使用 std::async 实现异步现在我们用std::async来改造它。std::async的基本用法是std::future返回值类型 future_obj std::async(启动策略, 可调用对象, 参数1, 参数2, ...);// async_solution.cpp #include iostream #include chrono #include thread #include future // 引入future头文件 // 耗时的任务函数保持不变 void processBigFile(const std::string filename) { std::cout [异步任务开始] 处理文件: filename std::endl; std::this_thread::sleep_for(std::chrono::seconds(3)); std::cout [异步任务完成] 文件 filename 处理完毕 std::endl; } int main() { std::cout 主线程用户点击了‘处理文件’按钮。 std::endl; // 关键步骤使用 std::async 异步启动任务 // std::launch::async 策略表示立即在新线程中执行任务 auto future_result std::async(std::launch::async, processBigFile, user_data.zip); std::cout 主线程异步任务已启动不会阻塞我可以立刻做其他事情。 std::endl; // 模拟主线程继续处理其他工作比如更新UI、响应其他事件 for (int i 0; i 5; i) { std::cout 主线程正在处理其他工作... ( i1 /5) std::endl; std::this_thread::sleep_for(std::chrono::milliseconds(500)); // 模拟其他工作耗时 } std::cout 主线程其他工作处理完毕现在等待文件处理结果如果需要。 std::endl; // 如果需要获取异步任务的结果本例中processBigFile返回void所以是等待完成 // future_result.get() 会阻塞直到异步任务完成并返回结果。 // 对于返回void的函数get()只是等待完成。 future_result.get(); // 等待异步任务结束 std::cout 主线程所有任务完成程序退出。 std::endl; return 0; }代码解释std::async(std::launch::async, processBigFile, “user_data.zip”)这行代码是异步的核心。它告诉C运行时“请以异步策略在新线程中调用processBigFile函数参数是”user_data.zip”并给我一个代表未来结果的凭证future”。auto future_result编译器自动推导出future_result的类型是std::future。因为processBigFile返回void。调用std::async后主线程立即继续执行打印后续消息并模拟处理其他工作。与此同时processBigFile函数在另一个线程中并发执行。future_result.get()这是同步点。主线程执行到这里时如果异步任务还没完成主线程会阻塞等待直到任务完成。对于无返回值的任务get()的作用就是等待任务结束保证异步任务的副作用如处理完文件在主线程继续后续关键流程前完成。运行这个程序你会看到“主线程正在处理其他工作…”的消息与“[异步任务开始]…”的消息交错出现具体顺序取决于操作系统调度直观地展示了并发执行。5. 处理有返回值的异步任务上面的例子任务没有返回值。更常见的情况是我们启动一个异步计算并需要在未来获取计算结果。std::future的强大之处就在这里。// async_with_return.cpp #include iostream #include future #include chrono #include thread // 一个模拟的耗时计算函数返回计算结果 int expensiveComputation(int base) { std::cout 计算任务在线程中开始参数: base std::endl; std::this_thread::sleep_for(std::chrono::seconds(2)); // 模拟计算耗时 int result base * base; // 假设进行复杂的计算这里简化为平方 std::cout 计算任务完成结果: result std::endl; return result; } int main() { std::cout 主线程启动一个异步计算任务。 std::endl; // 启动异步任务它会返回一个 std::futureint std::futureint future_result std::async(std::launch::async, expensiveComputation, 10); std::cout 主线程任务已提交future已获取。继续做其他事... std::endl; std::this_thread::sleep_for(std::chrono::seconds(1)); std::cout 主线程其他事情做完了现在需要计算结果了。 std::endl; // 通过 future.get() 获取结果。如果任务未完成会阻塞等待。 int computed_value future_result.get(); std::cout 主线程获取到异步计算的结果 computed_value std::endl; std::cout 主线程使用结果进行后续操作... std::endl; // 例如computed_value * 2 ... return 0; }关键点std::future这里的模板参数int指明了这个future对象未来持有的值的类型是int。future_result.get()调用这个方法会返回int类型的计算结果。get()方法只能调用一次第二次调用会导致未定义行为通常程序崩溃。因为get()在取出值的同时也移动或消耗了future内部的状态。6. 异步任务的启动策略async vs deferredstd::async的第一个参数是启动策略它决定了任务何时、以何种方式执行。这是一个容易混淆但非常重要的知识点。#include iostream #include future #include chrono #include thread void task(const std::string name) { std::cout 任务[ name ] 正在运行线程ID可能变化。 std::endl; } int main() { std::cout \n 测试 std::launch::async std::endl; // 策略1异步执行 (std::launch::async) // 任务会立即在一个新线程中开始执行或从线程池取线程 auto future_async std::async(std::launch::async, task, Async策略); std::cout 主线程async策略下任务可能已开始并发执行。 std::endl; future_async.wait(); // 等待任务完成 std::cout Async任务已确认完成。\n std::endl; std::cout 测试 std::launch::deferred std::endl; // 策略2延迟执行 (std::launch::deferred) // 任务不会立即执行。它被延迟到第一次调用 future.get() 或 future.wait() 时 // 并且在调用者的线程中同步执行 auto future_deferred std::async(std::launch::deferred, task, Deferred策略); std::cout 主线程deferred策略下任务尚未开始。 std::endl; std::this_thread::sleep_for(std::chrono::seconds(1)); std::cout 主线程现在调用 future.wait()... std::endl; future_deferred.wait(); // 此时task(Deferred策略) 才在主线程中执行 std::cout Deferred任务已确认完成。\n std::endl; std::cout 测试默认策略不指定 std::endl; // 策略3默认策略 (std::launch::async | std::launch::deferred) // 这是最微妙也最容易出问题的地方。标准允许实现自行选择是立即异步执行还是延迟执行。 // 这意味着任务的并发性是不确定的不要依赖其并发行为。 auto future_default std::async(task, 默认策略); std::cout 主线程默认策略下任务可能异步也可能延迟行为依赖编译器实现。 std::endl; future_default.wait(); return 0; }核心结论与最佳实践std::launch::async明确要求异步并发执行。这是你最常需要、行为最确定的策略。如果你希望任务一定在后台运行就用它。std::launch::deferred延迟的同步执行。这本质上是一种“惰性求值”并没有创建新线程。适用于你不确定是否需要执行该任务或者想将计算延迟到最后一刻的场景。它没有并发效果。默认策略不传参行为由实现定义。GCC和Clang的libstdc通常表现为async但MSVC在某些版本/设置下可能表现为deferred。为了代码的可移植性和明确性永远不要依赖默认策略。总是显式指定std::launch::async。最佳实践代码// 总是显式指定启动策略避免歧义 auto my_future std::async(std::launch::async, myFunction, arg1, arg2);7. 运行结果验证与调试技巧运行上述任何一个示例程序观察输出顺序。一个成功的异步程序其输出顺序通常是不确定的async策略下这正说明了主线程和异步任务在同时运行。如何验证异步确实发生了观察输出交错主线程的打印和任务线程的打印会混合出现。测量总时间对于async策略如果主线程在等待get()之前做了其他工作且其他工作与异步任务耗时重叠那么程序的总执行时间会小于同步执行时间 主线程其他工作时间。使用调试器在VS Code、CLion或Visual Studio中设置断点你可以看到程序在执行std::async后会同时存在多个活跃的线程栈。一个简单的验证脚本// verify_async.cpp #include iostream #include future #include chrono #include thread int main() { auto start std::chrono::high_resolution_clock::now(); auto future std::async(std::launch::async, [](){ std::this_thread::sleep_for(std::chrono::seconds(3)); return 42; }); // 主线程也睡眠2秒模拟其他工作 std::this_thread::sleep_for(std::chrono::seconds(2)); int result future.get(); // 这里最多等待1秒因为任务已执行了2秒还剩1秒 auto end std::chrono::high_resolution_clock::now(); std::chrono::durationdouble elapsed end - start; std::cout “计算结果: ” result std::endl; std::cout “总耗时: ” elapsed.count() “ 秒” std::endl; // 总耗时应该接近3秒max(任务耗时3s 主线程工作2s 等待1s)而不是5秒3s2s。 return 0; }8. 常见问题与排查思路问题现象可能原因排查方式解决方案编译错误std::async未定义编译器未启用C11或更高模式或未包含头文件。检查编译命令是否包含-stdc11或更高检查源码是否#include。确保使用正确的编译标志和头文件。程序崩溃错误与future相关多次调用了future.get()或future.share()后状态异常。检查代码逻辑确保对同一个future对象get()只调用一次。get()只能调用一次。如果需要共享结果使用future.share()获取std::shared_future。异步任务没有执行1. 使用了std::launch::deferred策略且从未调用get()/wait()。2. 使用了默认策略编译器实现选择了延迟执行。1. 检查启动策略。2. 在调试器中查看线程数量是否增加。始终显式使用std::launch::async以确保任务被异步启动。任务抛出的异常在主线程中捕获不到异常在异步任务线程中抛出默认会终止整个程序。任务函数内部做好异常处理或通过future.get()在主线程捕获。在future.get()调用处用try-catch块包裹。get()会将异步任务中的异常重新抛出到主线程。性能没有提升甚至更差1. 任务过于轻量创建线程的开销大于收益。2. 任务数量巨大导致线程频繁创建销毁或过度竞争。3. 大量任务阻塞在I/O上线程数过多。使用性能分析工具评估任务耗时和线程切换开销。对于轻量级任务考虑批量处理或使用更轻量的并发机制如线程池。对于I/O密集型任务考虑使用异步I/O库如asio而非单纯线程。future析构时程序阻塞这是std::async一个非常重要的特性如果future是以async策略启动的并且其析构发生在任务完成之前析构函数会阻塞等待任务完成。观察程序退出或作用域结束时的行为。如果需要“发后即忘”fire-and-forget且不关心结果确保将future存储到生命周期足够长的对象中如全局变量、类成员或者使用其他机制如直接创建std::thread并detach但需谨慎。关于“future析构阻塞”的示例与解释void fireAndForget() { // 这个函数启动一个异步任务但不保存其future std::async(std::launch::async, [](){ std::this_thread::sleep_for(std::chrono::seconds(5)); std::cout “后台任务完成\n”; }); // 临时future对象在此处析构由于任务需要5秒析构函数会等待5秒导致函数无法立即返回。 std::cout “函数不会立即打印此消息会等待5秒\n”; } void fireAndForgetCorrect() { // 正确做法如果真想“发后即忘”使用 std::thread 并 detach (需自行处理异常和生命周期) std::thread([](){ try { std::this_thread::sleep_for(std::chrono::seconds(5)); std::cout “后台任务完成\n”; } catch (...) { /* 处理异常 */ } }).detach(); // 分离线程让其独立运行 std::cout “函数立即返回不会等待\n”; // 注意detach 后主线程必须保证程序运行时间足够长让后台线程完成。 // 否则程序退出时后台线程可能被强制终止。 }这个特性意味着std::async配合std::future提供了一种简单的任务生命周期管理只要持有future就能确保任务完成或知道其状态。这避免了资源泄漏但要求开发者理解其阻塞析构的语义。9. 最佳实践与工程建议掌握了基础用法后要在实际项目中用好std::async还需要遵循以下最佳实践明确指定启动策略如前所述总是使用std::launch::async来获得确定的异步行为。// 好 auto f std::async(std::launch::async, func, args...); // 不好行为依赖实现 auto f std::async(func, args...);处理好异常异步任务中的异常不会自动崩溃整个程序但会在future.get()时抛出。务必在主线程捕获。std::futureint f std::async(std::launch::async, [](){ throw std::runtime_error(“任务出错了”); return 1; }); try { int r f.get(); } catch (const std::exception e) { std::cerr “捕获到异步任务异常: ” e.what() std::endl; }限制并发数量不要无节制地创建大量std::async任务。每个任务默认都可能对应一个系统线程过量线程会导致调度开销剧增。对于大量小任务应考虑使用线程池如std::execution::par配合算法或第三方库如 Intel TBB、微软 PPL。// 错误示范可能瞬间创建大量线程 for (int i 0; i 10000; i) { futures.push_back(std::async(std::launch::async, processItem, data[i])); } // 正确思路使用线程池或任务队列控制并发度。区分CPU密集型和I/O密集型任务CPU密集型任务主要消耗CPU。线程数最好接近CPU核心数std::async可用但需控制总数。I/O密集型任务大部分时间在等待I/O磁盘、网络。可以使用比核心数更多的线程但更好的方式是使用异步I/O如Boost.Asio、libuv让少数线程通过事件循环处理大量I/O操作效率远高于阻塞式多线程。使用std::future的状态查询在等待结果前可以检查任务状态。std::futureint f std::async(std::launch::async, heavyTask); // ... 做其他事情 ... if (f.wait_for(std::chrono::milliseconds(100)) std::future_status::ready) { // 任务在100毫秒内完成了 int result f.get(); } else { // 任务还没完成可以决定继续等待或做其他处理 std::cout “任务还在进行中...\n”; }对于需要多个地方等待的结果使用std::shared_futurestd::futureint f std::async(std::launch::async, [](){ return 42; }); std::shared_futureint sf f.share(); // 将 future 转为 shared_future // 现在 sf 可以被复制多个线程可以安全地调用 sf.get()作为更复杂并发模式的基石std::async适合简单的“任务-结果”模型。对于更复杂的流水线、依赖任务图、工作窃取等模式你需要组合多个future如std::when_any,std::when_allC17或使用更专业的并发库。C的异步编程之旅从std::async开始是最佳选择。它用极简的接口让你快速体验到并发带来的性能提升而无需过早陷入线程同步的泥潭。记住今天的核心用std::launch::async启动任务用std::future接收结果在get()时处理异常。先让程序“动起来”再去考虑性能优化和更复杂的模式。当你需要处理成百上千的微任务或者需要极致的控制力时才是研究线程池、无锁编程和协程的时候。

相关新闻

Streamlink:解锁纯净直播体验的终极命令行工具

Streamlink:解锁纯净直播体验的终极命令行工具

2026/7/21 14:07:28

Streamlink:解锁纯净直播体验的终极命令行工具 【免费下载链接】streamlink Streamlink is a CLI utility which pipes video streams from various services into a video player 项目地址: https://gitcode.com/gh_mirrors/st/streamlink 你是否厌倦了网页…

国家中小学智慧教育平台电子课本下载器:3分钟搞定所有教材PDF的终极指南

国家中小学智慧教育平台电子课本下载器:3分钟搞定所有教材PDF的终极指南

2026/7/21 13:57:28

国家中小学智慧教育平台电子课本下载器:3分钟搞定所有教材PDF的终极指南 【免费下载链接】tchMaterial-parser 国家中小学智慧教育平台 电子课本下载工具,帮助您从智慧教育平台中获取电子课本的 PDF 文件网址并进行下载,让您更方便地获取课本…

电商导购APP搜索体验升级:基于Elasticsearch的商品优惠券全文检索优化

电商导购APP搜索体验升级:基于Elasticsearch的商品优惠券全文检索优化

2026/7/21 13:57:28

电商导购APP搜索体验升级:基于Elasticsearch的商品优惠券全文检索优化 大家好,我是省赚客APP研发者微赚淘客! 在电商导购领域,搜索是连接用户与海量优惠券的核心桥梁。随着商品库的指数级增长,传统的数据库模糊查询&…

如何高效使用cJSON:C语言JSON处理的完整解决方案

如何高效使用cJSON:C语言JSON处理的完整解决方案

2026/7/21 20:27:56

如何高效使用cJSON:C语言JSON处理的完整解决方案 【免费下载链接】cJSON Ultralightweight JSON parser in ANSI C 项目地址: https://gitcode.com/gh_mirrors/cj/cJSON 你是否曾在C语言项目中为JSON数据解析而烦恼?面对复杂的网络API交互或配置文…

小米多线圈无线快充技术解析与拆解

小米多线圈无线快充技术解析与拆解

2026/7/21 20:27:56

1. 小米多线圈无线充的产品定位与技术突破当苹果在2017年首次展示AirPower概念时,整个科技圈都为这种"随意放置即可充电"的体验感到兴奋。然而三年后,苹果却因技术难题宣布取消该项目。这个未完成的承诺,最终被雷军带领的小米团队在…

Poco跨引擎UI自动化测试框架:从入门到精通的完整指南

Poco跨引擎UI自动化测试框架:从入门到精通的完整指南

2026/7/21 20:27:56

Poco跨引擎UI自动化测试框架:从入门到精通的完整指南 【免费下载链接】Poco A cross-engine test automation framework based on UI inspection 项目地址: https://gitcode.com/gh_mirrors/poc/Poco Poco是一个强大的跨引擎UI自动化测试框架,专为…

3个知识管理难题:用SiYuan打造你的专属数字书房

3个知识管理难题:用SiYuan打造你的专属数字书房

2026/7/21 20:27:56

3个知识管理难题:用SiYuan打造你的专属数字书房 【免费下载链接】siyuan A privacy-first, self-hosted, fully open source personal knowledge management software, written in typescript and golang. 项目地址: https://gitcode.com/GitHub_Trending/si/siyu…

深入理解SoC时钟域:从芯片手册到实战配置的功耗管理艺术

深入理解SoC时钟域:从芯片手册到实战配置的功耗管理艺术

2026/7/21 20:27:56

1. 从芯片手册到实战:为什么我们需要深入理解SoC时钟域?如果你是一名嵌入式软件工程师,或者正在从事汽车电子、高性能计算等领域的SoC开发,那么“时钟域”这个词对你来说一定不陌生。但很多时候,我们只是从芯片手册的表…

Autotest硬件兼容性测试:新硬件验证的终极完整指南 [特殊字符]

Autotest硬件兼容性测试:新硬件验证的终极完整指南 [特殊字符]

2026/7/21 20:17:56

Autotest硬件兼容性测试:新硬件验证的终极完整指南 🚀 【免费下载链接】autotest Autotest - Fully automated tests on Linux 项目地址: https://gitcode.com/gh_mirrors/au/autotest 在当今快速发展的硬件技术时代,确保新硬件与Linu…

微服务进阶:服务网格与Istio

微服务进阶:服务网格与Istio

2026/7/21 5:45:57

541|微服务进阶:服务网格与Istio 上篇文章我们聊了微服务的基本概念和拆分方法。 但微服务多了,问题也多了: 服务之间怎么通信? 怎么监控每个服务的调用链路? 熔断、限流、重试怎么做? 安全认证怎么统一? 以前这些都靠SDK库(比如Hystrix、Feign),每个服务都要集成…

零售超级终端全域协同:ShareKit 碰一碰商品流转业务落地案例

零售超级终端全域协同:ShareKit 碰一碰商品流转业务落地案例

2026/7/21 9:56:14

一、零售门店全域协同业务背景与行业痛点 1.1 门店超级终端设备矩阵(连锁便利店/商超标准配置) 自助收银Kiosk一体机:顾客结算、自助核销优惠券、商品素材预览;运营折叠平板:店长后台商品上新、图片录入、活动配置、…

噗叽短视频界面分析

噗叽短视频界面分析

2026/7/21 3:09:32

1 和小红书类似,可以采用类似判断方法------------其实他比小红书好判断,因为他没有图片,控件位置几乎是固定的,都不用判断------------2 因为他没有点赞按钮------------而且几乎所有控件位置都是完全一样的,所以我就…

GraphRAG Local + Ollama:微软知识图谱本地化

GraphRAG Local + Ollama:微软知识图谱本地化

2026/7/21 0:06:35

普通 RAG 有个老毛病:你问它「这堆文档整体在讲什么」,它答不上来。因为它只会把问题切成向量,去几十个文本块里捞最相似的几段拼给模型看。可「整体讲什么」这种问题,答案根本不在任何单独一段里——它散在全篇的联系里。 微软的…

AI 数据产品化思考:让分析能力变成可售卖的数据服务

AI 数据产品化思考:让分析能力变成可售卖的数据服务

2026/7/21 0:06:35

AI 数据产品化思考:让分析能力变成可售卖的数据服务 大家好,我是朱大喜。这周一直在复盘具体的项目和技术,最后一篇聊点不一样的东西——数据产品化。做了这么多年数据分析,我发现一个规律:能卖出去的从来不是"分…

基于人机协作的 AI 研发新体系架构:从 Harness 工程到 Loop 工程实践

基于人机协作的 AI 研发新体系架构:从 Harness 工程到 Loop 工程实践

2026/7/21 0:06:35

本文完整呈现了企业级 AI Coding 落地的核心方法论:从 Harness 工程的微观/宏观定义,到 Loop 工程的六大构建模块,再到基于 SDD(规范驱动开发)的工程化落地路径。干货较多,建议收藏细读。 我从 22 年开始就…