我有一个使用 dropwizard 和 jersey 构建的基本 kotlin Web 服务器应用程序,它使用线程来处理请求。我最近读了很多关于 kotlin 协程的文章,并看到了关于优先使用它们而不是线程的文章,我想知道如何将它们引入我的应用程序?在我看来,除非我将整个应用程序配置为从头开始在线程上使用协程并使用协程处理请求,否则尝试引入它们将是一个坏主意,因为会有两种不同的冲突并发调度模式。有没有人对在基于线程的应用程序中使用协程的良好实践有什么建议?
注意:我知道在协程系统中,我可能希望在启动时启动与内核数量一样多的线程,以帮助支持并行性和并发性,但我更专注于在申请代码。
通常情况下,这取决于情况,但我认为你仍然可以分析它,甚至不需要关注 Web 服务器,几乎任何利用现有框架/库的场景都应该有或多或少相同的考虑因素。
如果您在一个框架之上实现您的代码,该框架的合同基本上指定“这是一个处理 X 的线程,在您完成之前它是您的”,那么如果您引入不同的“嵌套”线程模型,那么大多数情况下都没有关系,框架不会关心您此时如何细分任务(不过也有例外,例如 JVM 中的 fork-join 池,请参阅例如 this JUnit 问题)。
这并不意味着它会给您带来好处。对于处理“小”请求的 Web 服务器来说,除非整个框架可以重用线程,否则它肯定不会帮助您扩展服务器的容量,但如果处理请求的逻辑需要以某种方式分解工作,那就是另一回事了;请参阅此示例。
此外,框架的契约可能有限制,实际上会禁止更改线程模型。我想说,框架通常依赖线程局部变量来处理和传播框架提供的其他实用程序可以使用的状态,因此您最终可能会得到在某些上下文中工作的组件,但由于这种状态而不能在其他上下文中工作您自己的代码看不到并且是必需的。
在我看来,这些情况下的良好实践基本上可以归结为:如果您对所使用的框架的技术细节有足够的了解,那么自然就会知道什么是可能的,什么是不可能的;如果你不够理解(或者框架的文档不够好),就不要这样做。并始终衡量您的场景中的性能并进行比较。