【问题标题】:Will I run into trouble with python's Global Interpreter Lock?我会遇到 python 的全局解释器锁的问题吗?
【发布时间】:2015-08-23 11:35:13
【问题描述】:

我知道这个问题相当高级,可能含糊不清。请询问您是否需要更多详细信息,我会尝试编辑。

我正在使用 QuickFixPython 绑定来同时使用来自大约 30 个市场的高吞吐量市场数据。大多数计算工作是通过multiprocessing 模块在单独的CPU 中完成的。这些并行进程由主进程在启动时产生。如果我希望通过QuickFix 以任何方式与市场互动,我必须在主进程中执行此操作,因此来自子进程的任何命令(例如输入订单)都必须通过管道传输(通过@ 987654328@ 对象我们将在执行前调用Q) 到主进程。

这引发了监控Q 的问题,这必须在主进程中完成。我不能使用Q.get(),因为此方法会阻塞,并且我的整个主进程将挂起,直到Q 中出现某些内容。为了减少延迟,我必须经常检查Q,大约每秒 50 次。我一直在使用apscheduler 来执行此操作,但我不断收到警告错误,指出错过了运行时。这些错误是一个严重的问题,因为它们使我无法轻松查看重要信息。

因此,我重构了我的应用程序以使用 MestreLion 发布的代码作为对 this question 的回答。这对我有用,因为它从主进程启动一个新线程,并且不打印错误消息。但是,我担心这会在未来造成严重的问题。

我知道 python 中的全局解释器锁(这就是我开始使用multiprocessing 模块的原因),但我不太了解它。由于我的应用程序的高频特性,我不知道Q监控线程和消耗大量传入消息的主进程是否会竞争资源并相互减慢。

我的问题:

  1. 在这种情况下我可能会遇到麻烦吗?

  2. 如果没有,我可以使用当前方法添加更多监控线程并且仍然可以吗?至少还有两件事我想高频监控。

谢谢。

【问题讨论】:

  • Queue.get 有一个阻塞参数,如果指定为 False阻塞,但引发异常,您可以轻松捕获。你试过吗?另外,你能限定“高频”吗?是你之前提到的30hz吗?那么恕我直言,您应该没有问题,即使监控三个来源。
  • 我的数据提供者有一些限制,我认为大约是 18-30 毫秒。这大约是每个市场消息之间的最短时间。在繁忙时期,这是相当数量的数据。至于我自己的监控,我提到了 50hz,而不是 30,但是是的,我认为这对我来说可能已经足够了。
  • 那么我真的怀疑你会遇到任何问题。顺便说一句,您如何将事件传播到主循环中?
  • @deets 由于某种原因使用线程时,我不需要传播到主循环中。如果我在Q 中得到任何东西,我可以直接从检查Q 的监控程序中调用方法(如发送订单)。

标签: python multithreading multiprocessing quickfix gil


【解决方案1】:

您已链接的@MestreLion's solution 在您的情况下每秒创建 50 个线程。

你只需要一个线程来消费队列而不阻塞主进程的其余部分:

import threading

def consume(queue, sentinel=None):
    for item in iter(queue.get, sentinel):
        pass_to_quickfix(item)

threading.Thread(target=consume, args=[queue], daemon=True).start()

在这种情况下,GIL 可能对性能有影响,也可能无关紧要。测量它。

【讨论】:

  • 我对线程模块或并发的细节不是很熟悉,所以你的贡献都很有帮助。我知道如何分析程序,但不确定如何衡量 GIL 性能?
  • @Wapiti:你不衡量 GIL 的性能(不管它是什么意思);您测量程序的时间性能。然后在解释结果时,您可能会得出结论,GIL 可以解释观察到的行为,或者可以使用其他原因进行解释。你应该知道一些显而易见的事情:不同的 Python 进程有自己的 GIL,Python 可能在 I/O 期间释放 GIL,各种 C 扩展如 regex、numpy、lxml 也可能释放 GIL。
  • 谢谢——我就是这么想的,但在你回答的最后,我的印象是你建议我测量 GIL。
【解决方案2】:

在不了解您的情况的情况下,很难说出具体的内容。您的问题表明,线程大部分时间都在通过get 等待,所以 GIL 不是问题。进程间通信可能会更早地导致问题。在那里,您可以考虑使用某种 TCP 套接字切换到另一个协议。然后,您可以使用select 而不是线程来编写更高效的调度程序,因为线程也很慢并且消耗资源。 select 是一个系统函数,它允许一次监控多个套接字连接,因此它可以根据连接数量进行非常高效的扩展,并且几乎不需要 CPU 资源进行监控。

【讨论】:

  • 在监控线程中我使用的是if Q.empty(): pass,所以它不会挂起。但也许只是打电话给get 会好得多,因为你说的原因?我实际上也在使用ZeroMQ 来合并来自另一个来源的数据,所以现在设置一些套接字内容。我不知道select。你能详细说明一下吗?
  • “线程也很慢而且很消耗资源。”——废话。为什么你认为:(async.io)poll、poll、poll、poll、read、poll、read、poll、read 比(线程)阻塞读取、读取、读取更快?
  • @J.F.Sebastian:哦,我明白了,你已经管理了一个有数千个线程的服务器......我从来没有说过轮询,我说的是select
  • 感谢select 的详细说明。这看起来是我应该知道的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-27
  • 2011-09-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多