【问题标题】:Python threading.stack_size() has no effectPython threading.stack_size() 没有效果
【发布时间】:2013-10-25 22:32:18
【问题描述】:

我正在尝试减少 python 脚本的堆栈大小以产生更多线程。 我是这样设置的

threading.stack_size(32768)

并在任何线程开始之前将其置于导入级别 问题是,它没有效果。 无论有没有它,我都可以启动确切数量的线程。 我在 Windows 7 机器 x64 上使用 Python 2.7 x86,可用内存超过 2.4GB。

关于为什么它没有效果的任何想法? 我真的在寻找一个解决方案,而不是我需要生成的线程数量上的 cmets。

我怀疑它与线程相关的 .pyc 文件有关,我记得我遇到过这样的情况,删除 .pyc 文件并让 python 在下次运行时重新编译它们会应用更改,但我不知道是什么与线程有关的文件。

如果我能得到任何帮助,我将不胜感激。

附:请不要推荐使用 Twisted 或 Asyncore,我知道它们更好,但我需要根据当前情况充分利用它,而不是重新设计整个代码。

【问题讨论】:

    标签: python multithreading networking stack-size


    【解决方案1】:

    Windows 上的最小线程堆栈大小可能至少为 64kB。 Quoting:

    The operating system rounds up the specified size to the nearest multiple of the
    system's allocation granularity (typically 64 KB). To retrieve the allocation
    granularity of the current system, use the GetSystemInfo function.
    

    因此尝试将其设置为 32kB 可能看起来很像尝试将其设置为 64kB。

    此外,CPython 在 Windows 上实现了threading.stack_size,因此它只控制初始提交堆栈。它不会尝试控制堆栈的保留内存。来自同一地点:

    The reserved memory size represents the total stack allocation in virtual memory.
    

    这意味着您的每个线程都用尽了虚拟内存中的保留内存大小。您没有提到在遇到错误之前您设法创建了多少线程,但我怀疑这足以耗尽您进程中的 addressable 内存(即使您正在运行,这可能是一个 32 位进程它在 Windows 7 x86-64 上,因为 CPython 构建/分发是 x86(-32))。

    也就是说,即使您(您的线程)没有使用内存并且即使您在系统上有更多的物理内存,Python 也无法通过其微小的 32 位来寻址额外的内存指针和超出您遇到的限制的新线程无法分配它们的保留内存(因为没有地址可以分配给它)。

    如果您希望能够更改每个线程保留的内存,那么您可能需要调用 CreateThread_beginthreadex,而不是 CPython 调用它。这可能意味着需要更改 CPython。

    也就是说,冒着让你对我大喊大叫的风险,我严重怀疑你需要的不仅仅是你已经可以创建的 1500 个线程。

    【讨论】:

    • 这是一个错误,是的,但即使有 64KB 它仍然没有效果。在阅读了一些关于这个之后,我发现线程模块(从那里线程导入其他东西)被编译成 python直接,并被视为对象,因此使其不可编辑。意思是,即使我编辑堆栈大小,它也没有效果,它仍然会威胁它为 1MB。我是对的吗?你能确认一下吗?
    • 我不知道您所说的“编辑堆栈大小”是什么意思。不过,我用更多可能相关的信息扩展了我最初的答案。
    • 我说的是 Windows 上每个线程的默认堆栈大小,默认为 1MB。 msdn.microsoft.com/en-us/library/windows/desktop/… 。因此,我正在尝试使用 threading.stack_size() 对其进行编辑,但在 Windows 上是徒劳的,因为处理该问题的 thread.h 文件将使用 Python 内置,因此忽略了我的请求。当我有 1600MB 的可用内存时,我能够生成 1500 个线程。我要做的是编辑默认的 Win32 堆栈大小,即 1MB。在这种情况下,如果我无法在 Windows 中编辑它,但需要在 Windows 上运行它,我该怎么办?
    • 我的回答谈到了与堆栈大小相关的两种不同大小。
    • 更详细地说,这是因为 CPython 调用 _beginthreadexCreateThread 时没有设置 STACK_SIZE_PARAM_IS_A_RESERVATION 标志。如果它设置了这个标志,那么你可以设置(降低)线程堆栈的保留内存。既然没有,你就不能。只要将保留内存设置为高于初始提交大小的值,您就不会看到降低初始提交大小带来的任何内存节省(大致而言,线程的内存成本是初始提交大小和保留内存)。
    【解决方案2】:

    一种可能性是获得 64 位版本的 python。这样你就不会遇到地址空间限制。您仍然会受到物理内存的限制,但这可能最终成为一个不太重要的限制。如果您没有其他选择,它还可以让您选择购买更多 RAM。唯一的问题是,据我了解,许多第 3 方 C 扩展在 Windows 上不支持 64 位,或者至少默认不提供 64 位构建。默认情况下,任何流行的 64 位 Linux 发行版都将使用 64 位 python,因此,如果您的软件未绑定到 Windows,这也可能是一个选项。如果您不顾一切,您可以在 Linux VM 中运行您的应用程序。

    我绝对可以理解我不想使用像 twisted 这样的异步编程风格来重写你的代码。一个可能更受欢迎的解决方案是使用用户空间绿色线程系统,如无堆栈 python 或 eventlets。这将需要一些移植,但比切换到基于反应堆的方法要少得多。同样,它是否合适取决于您的应用程序。

    【讨论】:

      【解决方案3】:

      操作系统还限制了您可以生成的线程/进程的数量。在 Linux (Redhat) 上,您可以使用 ulimit -u 进行检查。默认值为 1024 个进程/线程(内核在内部将线程视为进程--http://www.thegeekstuff.com/2013/11/linux-process-and-threads/)。这与其他 ulimit 值一起,可以在 /etc/security/limits.conf 中设置。 我不确定 Windows 的等价物是什么,但这将是 linux 用户的解决方案,能够产生更多线程/进程。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-08-19
        • 1970-01-01
        • 2017-07-22
        • 2020-01-10
        • 2018-01-10
        • 2012-10-30
        相关资源
        最近更新 更多