对于Python / Linux,最大线程限制实际上是一个不相关的问题吗?

时间:2012-04-27 03:58:24

标签: python multithreading thread-safety threadpool python-multithreading

我正在处理的当前Python应用程序需要使用1000+个线程(Pythons线程模块)。并不是说任何单个线程都在最大cpu周期工作,这只是我正在创建的Web服务器负载测试应用程序。 I.E.模拟200个firefox客户端,他们都渴望进入Web服务器并下载小型Web组件,基本上模拟人类在几秒钟内操作而不是微秒。

所以,我正在阅读各种主题,例如“Linux / Windows上支持python的线程数等等,我看到了很多不同的答案。一位用户说默认内存和Linux内核只留出8Meg的线程,如果它超过了那么线程开始被内核杀死。

有人说这对CPython来说不​​是问题,因为无论如何一次只运行1个线程(因为GIL)所以我们可以指定一个很多的线程???这有什么实际的真相?

2 个答案:

答案 0 :(得分:13)

  1. “由于GIL,一次运行一个线程。”好吧,有点。 GIL意味着一次只能有一个线程执行 Python 代码。但是,任何数量的线程都可能正在执行IO,各种其他系统调用或其他不支持GIL的代码。

    听起来你的线程主要是做网络I / O,任何数量的线程都可以同时进行I / O. GIL竞争可能相当激烈,有1000个线程,但你总是可以创建多个Python进程并在它们之间划分I / O线程(例如,fork在你开始之前几次。)

  2. “Linux内核默认只为线程留出8Meg。”我不确定你在哪里听到的。也许您实际听到的是“在Linux上,默认堆栈大小通常是8 MiB”,这是真的。每个线程将使用8 MiB的地址空间用于堆栈(64位没有问题)以及用于附加内存映射和线程进程本身的内核资源。您可以使用threading.stack_size库函数更改堆栈大小,如果您有很多线程没有进行深度调用,这会有所帮助。

    >>> import threading
    >>> threading.stack_size()
    0 # platform default, probably 8 MiB
    >>> threading.stack_size(64*1024) # 64 KiB stack size for future threads
    
  3. 此线程中的其他人建议使用异步/非阻塞框架。好吧,你可以做到。但是,在现代Linux内核上,多线程模型与异步(select / poll / epoll)I / O复用技术相竞争。重写代码以使用异步模型是一项非常重要的工作,所以如果我无法从线程模型中获得所需的性能,我只会这样做。如果你的线程真的试图模拟人类延迟(例如,大部分时间都在休眠),那么很多情况下异步方法实际上较慢。我不确定这是否适用于Python,单独减少GIL争用可能值得转换。

答案 1 :(得分:3)

这两者都是正确的:

  • 每个线程都有一个堆栈,如果你创建了足够的线程,你可以用完堆栈的地址空间。

  • Python也有一些名为GIL的东西,它一次只允许一个Python线程运行。但是,一旦Python代码调用C代码,该C代码就可以在运行不同的Python线程时运行。但是,Python中的线程仍然是物理的,并且仍然存在堆栈空间限制。

如果您计划建立多个连接,而不是使用多个线程,请考虑使用异步设计。 Twisted可能会在这里运作良好。