何时应该使用Tokio的`spawn_blocking`?

6
task文档中,有一节讲述了在异步代码中调用阻塞式代码的问题,以及应该避免过多地阻塞异步线程(https://docs.rs/tokio/1.21.2/tokio/task/index.html#blocking-and-yielding)。
文档还介绍了使用tokio::task::spawn_blocking解决这些问题,但我想知道什么情况下发送工作到另一个线程是推荐的?我目前正在编写一个程序,该程序恢复了大量的ecdsa签名,每个消息需要约100微秒,同时进行大量网络IO操作。作为具体的示例,这是否足以使用spawn_blocking呢?

这个回答解决了你的问题吗?为什么Future::select会优先选择睡眠时间更长的future? - Ömer Erden
这可能会更好地解释:如何封装future-rs中的阻塞I/O的最佳方法是什么? - Ömer Erden
2
我不确定我同意这是那些问题的重复 - 那些问题是关于如何处理阻塞,但这个问题更多地涉及“什么是阻塞(以及多少才算太多)”。 - Joe Clay
谢谢,这两篇帖子都很有帮助,但不完全是我想要的。 - boston
1个回答

12
Alice Rhyl(Tokio开发者之一)在关于异步代码中阻塞的博客文章中有很好的阐述。
其中对你的问题的关键部分如下:
“为了给出太多时间的概念,一个好的经验法则是,在每个.await之间不要超过10到100微秒。尽管如此,这取决于您正在编写的应用程序的类型。”
鉴于你每条消息花费100微秒,我认为你很可能已经到了将工作移到另一个线程的时候了。
该帖子还提供了一条指导性的经验法则,用于处理将工作移动到不同线程的方法:
- 对于同步IO,请使用`spawn_blocking`。 - 对于CPU密集型计算,请使用单独的fork-join线程池,例如`rayon`。 - 对于永久运行的同步工作(例如监听数据库连接),请生成自己的专用线程以避免从Tokio/Rayon线程池中取走一个线程。

谢谢!我记得一段时间前读过那篇文章,但没有完全掌握,会重新阅读。在这种情况下,由于恢复签名是CPU绑定的,像Rayon这样的东西不是最好的解决方案吗?(我从未使用过它,但听说过) - boston
1
@Boston:啊,我以为你提到的网络IO是最大的因素,而不是签名位。既然这样,Rayon可能值得考虑-当工作可以分解成可以在CPU核心之间分配的较小块时,这通常最有效。 - Joe Clay

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接