柴油机应该使用同步参与者 actix_web::web::block 还是 futures-cpupool 运行?
Posted
技术标签:
【中文标题】柴油机应该使用同步参与者 actix_web::web::block 还是 futures-cpupool 运行?【英文标题】:Should diesel be run using a sync actor, actix_web::web::block or futures-cpupool? 【发布时间】:2020-03-05 01:39:30 【问题描述】:背景
我正在开发一个通过 r2d2 使用柴油的 actix-web 应用程序,但我不确定如何最好地进行异步查询。我找到了三个看起来合理的选项,但不确定哪个最好。
可能的解决方案
同步演员
我可以使用the actix example,但它非常复杂,需要大量的样板来构建。希望有更合理的解决方案。
Actix_web::web::block
作为另一种选择,我可以使用 actix_web::web::block
将我的查询函数包装到未来,但我不确定这对性能的影响。
查询是否在同一个 Tokio 系统中运行?根据我在源代码中可以找到的内容,it creates a thread in the underlying actix-web threadpool。有问题吗?
如果我没看错代码,r2d2 在获取连接时会阻塞其线程,这会阻塞部分核心 actix-web 池。与数据库查询相同。如果我执行的查询多于该池中的线程数,这会阻止所有 actix-web 吗?如果是这样,问题就大了。
期货-cpupool
最后,可能会有一些不必要的开销的安全赌注是futures-cpupool。主要问题是这意味着向我的项目添加另一个 crate,尽管我不喜欢在我的应用程序中不必要地浮动多个 cpu 池的想法。
由于 r2d2 和柴油都会阻塞,因此这里有很多棘手的问题。
最重要的是,不要与不使用同一个 r2d2 池的任何东西共享这个 cpupool(因为创建的所有线程可能只是阻塞等待 r2d2 连接,当工作存在时锁定整个池)。
其次(更明显一点),因此您不应该比池中的线程拥有更多的 r2d2 连接,反之亦然,因为较大的连接会浪费资源(未使用的连接/线程不断阻塞)(可能多一个线程,由 OS 调度程序而不是 cpupool 调度程序进行更快的连接切换)。
最后,请注意您使用的是什么数据库以及那里的性能。在写入繁重的 sqlite 应用程序中运行单个连接 r2d2 和池中的单个线程可能是最好的(尽管我会推荐一个合适的数据库)。
旧答案
可能有效的旧解决方案
https://www.reddit.com/r/rust/comments/axy0hp/patterns_to_scale_actixweb_and_diesel/
本质上,推荐Futures-cpupool。
What is the best approach to encapsulate blocking I/O in future-rs?
推荐 Futures-cpupool 用于一般情况。
不起作用的旧解决方案
https://www.reddit.com/r/rust/comments/9fe1ye/noob_here_can_we_talk_about_async_and_databases/
对旧的 actix-web 版本进行了非常好的修复。据我所知,请求中不再有 cpu 池。
【问题讨论】:
从 this issue 中的 cmets 看来,futures-cpupool
是推荐的解决方法,因为 Diesel 缺乏对 async
的支持。
这更像是一个通用的解决方案。我希望有一些可以利用 actix 系统的东西。尽管如此,我现在将深入研究 futures-cpupool 以寻找问题。
欢迎来到 Stack Overflow! What is the best approach to encapsulate blocking I/O in future-rs? 的答案似乎可以回答您的问题。如果没有,请edit您的问题来解释差异。否则,我们可以将此问题标记为已回答。
由于 cpupool 还与 r2d2 中的阻塞连接池交互,我不确定如何最好地解决这个问题。我现在正在自己研究它,很快就会更新。
【参考方案1】:
我将使用 futures-cpupool。由于我的交互的阻塞性质,这是最好的解决方案。
使用 actix_web::web::block 就足够了,但会在 actix 中使用共享线程池(由于阻塞调用,我使用它会阻塞整个线程池并干扰给 actix_web 的其他任务) .
最好使用 futures-cpupool 为每个数据库创建一个单独的线程池,仅用于数据库交互。这样,您可以将需要相互等待的所有任务(当任务多于连接时)分组到一个池中,防止它们阻塞任何其他不需要连接的任务,并可能将线程数限制为连接数(以便任务仅在不会被阻塞时安排)。
在您只想使用一个数据库连接(或很少)的情况下,同步参与者是一个不错的选择。它将像一个带有一个线程的futures-cpupool,确保所有任务一次运行一个,除了它将使用actix-web的底层线程之一而不是单独的线程(因此,仅适用于很少的连接) .不过,我发现样板文件太大了,不值得。
【讨论】:
阅读我上面的发现 — 请将与答案相关的信息放在答案中,而不是问题中。 你会推荐多大的池?以上是关于柴油机应该使用同步参与者 actix_web::web::block 还是 futures-cpupool 运行?的主要内容,如果未能解决你的问题,请参考以下文章