我 运行 会因 python 的全局解释器锁而陷入困境吗?

Will I run into trouble with python's Global Interpreter Lock?

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

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

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

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

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

我的问题:

  1. 在这种情况下我会 运行 惹上麻烦吗?

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

谢谢。

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

@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 可能对性能有影响,也可能没有影响。测量一下。