像这样将上下文注入 eventlet 线程安全吗?

Is it safe to inject context into a eventlet thread like this?

我需要注入线程级上下文信息以进行日志记录和调试。有人告诉我这可能不安全。

greenthread = worker_pool.spawn(run_worker, args, handle_result)
# this logging_context attribute will be accessed by the logging library
greenthread.__dict__['logging_context'] = 'data for logging'
greenthread.link()

虽然这肯定不是您经常想要做的事情,但这是我可以设置线程本地全局常量的唯一方法,记录器可以访问它。

稍后记录器可以通过

访问它
eventlet.getcurrent().logging_context

据我对 python 的了解,我不明白这有什么不安全的地方,为什么其他人说这可能会导致灾难?


虽然我认为它是一个相当丑陋的猴子补丁,但我并不是在创建全局可变状态。我正在创建一个线程局部常量,该常量在线程甚至 运行.

之前实例化

我同意,"safe/unsafe" 是为了痴迷 parents。作为程序员,我们可以以更严格和有用的方式定义对问题的预期。

  • 这种方法现在有效,所以当 eventlet 和 greenlet 版本被锁定时,它会起作用并且一切都很好。
  • 您将在 spawn 之后更改 Greenthread 属性。现在在新生成的 greenthread 执行之前需要 sleep() 或其他方式屈服于 "event loop",但这种行为将来可能会改变。这意味着 run_worker 可能已经 运行ning。在允许它们 运行.
  • 之前,您可以使用 eventlet.pools.Pool() 来管理正确的设置和 link greenthreads
  • 将来它可能会中断,因为 greenthread 会 __slots__ 以节省内存,或者出于其他原因的特定 __setattr__ 实现。
  • 您正在做的事情已经过测试和支持 API,它被称为线程本地存储。您可以像常规 Python threadlocal object 一样使用它,但使用 threading[1].
  • 的补丁版本
  • 你可能更喜欢 Logbook[2],它有更简洁的方法来做同样的事情(在后台使用 threadlocal)。

threadlocal 路线的示例代码:

def add_logging_context(context, fun, *a, **kw):
  tl = threading.local()
  tl.logging_context = context
  return fun(*a, **kw)

pool.spawn(add_logging_context, 'data for logging', run_worker, args, handle_result)

[1] http://eventlet.net/doc/patching.html

[2] https://logbook.readthedocs.io/en/stable/