15

背景

我正在通过 r2d2 使用柴油开发一个 actix-web 应用程序,并且不确定如何最好地进行异步查询。我找到了三个看起来合理的选项,但不确定哪个是最好的。

潜在的解决方案

同步演员

对于一个我可以使用actix 示例,但它非常复杂,并且需要大量的样板来构建。我希望有一个更合理的解决方案。

Actix_web::web::block

作为另一种选择,我可以使用actix_web::web::block将我的查询函数包装到未来,但我不确定这对性能的影响。

然后查询是否在同一个 Tokio 系统中运行?根据我在源代码中可以找到的内容,它在底层 actix-web threadpool 中创建了一个线程。那是问题吗?

如果我没看错代码,r2d2 在获取连接时会阻塞它的线程,这会阻塞部分核心 actix-web 池。与数据库查询相同。如果我执行的查询多于该池中的线程数,这会阻止所有 actix-web 吗?如果是这样,问题就大了。

期货-cpupool

最后,可能有一些不必要的开销的安全赌注是futures-cpupool。主要问题是这意味着在我的项目中添加另一个板条箱,尽管我不喜欢在我的应用程序中不必要地浮动多个 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。

在 future-rs 中封装阻塞 I/O 的最佳方法是什么?

一般情况下推荐 Futures-cpupool。

不起作用的旧解决方案

https://www.reddit.com/r/rust/comments/9fe1ye/noob_here_can_we_talk_about_async_and_databases/

对旧的 actix-web 版本的一个非常好的修复。从我可以找到的请求中不再有 cpu 池。

4

1 回答 1

3

我将使用期货-cpupool。由于我的交互的阻塞性质,这是最好的解决方案。

使用 actix_web::web::block 就足够了,但会在 actix 中使用共享线程池(由于阻塞调用,我使用它会阻塞整个线程池并干扰给 actix_web 的其他任务)。

最好使用 futures-cpupool 为每个数据库创建一个单独的线程池,仅用于数据库交互。这样,您可以将需要相互等待的所有任务(当任务多于连接时)分组到一个池中,防止它们阻塞任何其他不需要连接的任务,并可能限制线程数到连接数(以便任务仅在不会被阻止时安排)。

在您只想使用一个数据库连接(或很少)的情况下,同步参与者是一个不错的选择。它将像一个带有一个线程的futures-cpupool,确保所有任务一次运行一个,除了它将使用actix-web的底层线程之一而不是单独的线程(因此,仅适用于很少的连接) . 不过,我发现样板文件太大了,不值得。

于 2019-11-08T14:54:21.143 回答