C++ 客户端库中的后台线程

本指南介绍了 C++ 客户端库使用的线程模型,并展示了如何在应用中替换默认线程池。

目标

  • 说明 C++ 客户端库的默认线程处理模型。
  • 说明如何针对需要覆盖这些默认设置的应用覆盖这些设置。

为什么客户端库使用后台线程?

客户端库中的大多数函数都使用调用该函数的线程来完成所有工作,包括对服务的任何 RPC 和/或刷新用于身份验证的访问令牌。

异步函数本质上无法使用当前线程来完成其工作。某个单独的线程必须等待工作完成并处理响应。

在长时间运行的操作中阻塞调用线程也是一种浪费,因为服务可能需要几分钟或更长时间才能完成工作。对于此类操作,客户端库会使用后台线程定期轮询长时间运行的操作的状态。

哪些函数和库需要后台线程?

对于某种类型 T,返回 future<T> 的函数使用后台线程等待工作完成。

并非所有客户端库都具有异步函数或长时间运行的操作。 不需要它们的库不会创建任何后台线程。

您可能会注意到应用中存在其他线程,但这些线程可能是由 C++ 客户端库(例如 gRPC)的依赖项创建的。这些线程通常不太有趣,因为没有任何应用代码会在这些线程中运行,它们仅用于辅助功能。

这些后台线程对我的应用有何影响?

与应用的其余部分一样,这些线程会争用 CPU 和内存资源。如果需要,您可以创建自己的线程池,以便精细控制这些线程使用的任何资源。有关详细信息,请参见下文。

我的任何代码是否在这些线程中运行?

可以。将回调附加到 future<T> 时,回调几乎总是由某个后台线程执行。只有在您附加回调时 future<T> 已满足的情况下,才不会发生这种情况。在这种情况下,回调会在附加回调的线程的上下文中立即运行。

例如,假设某个应用使用 Pub/Sub 客户端库。Publish() 调用会返回一个 future,应用可以在执行一些工作后附加回调:

namespace pubsub = ::google::cloud::pubsub;