我是线程新手,并且想知道为各种任务(在服务器环境中)产生大量线程是否不好。与更线性的编程相比,线程占用更多的内存/ CPU吗?
答案 0 :(得分:18)
如果要使用多个线程,则必须考虑多个事项:
我从中得出的结论:
答案 1 :(得分:5)
由于您不熟悉线程,因此还有其他值得注意的事项 - 我更倾向于将其视为值的并行范围。
对于任何给定对象的传统线性/顺序编程,您只有一个线程访问和更改一段数据。由于具有词法范围,这通常是安全的。具体而言,一个函数可以对变量的值进行操作,而不会影响全局值。如果您没有词法范围或不良的词法范围,那么在一个函数中更改名为“foo”的变量的值会影响另一个名为“foo”的变量。现在这种问题不太常见,但仍然很常见,可以暗指。
使用线程,您会以更微妙的方式遇到相同的问题。虽然你仍然有词汇范围帮助你 - 因为一个函数内的局部值“X”独立于另一个函数中称为“X”的另一个本地值,数据结构是可变的这一事实是线程中错误的主要来源。 / p>
具体来说,如果函数传递了一个可变值,那么在线程环境中除非你已经注意了,否则该函数不能保证该值不被其他任何东西改变。
此共享状态是线程系统中可能有90-99%的错误的来源,并且可能非常难以调试。因此,如果您要编写一个线程系统,您应该记住共享值的行进距离 - 即并行访问的范围。
为了限制错误,您可以使用一些已知可行的选项:
1与unix管道最相当。 3在逻辑上等同于版本控制,通常称为软件事务存储器。
1& 3是Kamaelia支持的并发模式,旨在消除由2级引起的错误。(披露,我运行Kamaelia项目)2不受支持,因为它依赖于“始终把一切都做对了”。
无论您使用哪种方法来解决问题,请记住这个问题,以及处理问题的方法,并提前规划您打算如何处理问题,这样可以免除以后的麻烦。< / p>
答案 2 :(得分:4)
这取决于平台。
Windows线程在创建时必须提交大约1MB的内存。最好是拥有某种线程池,而不是像疯子一样产生线程,以确保你永远不会分配超过固定数量的线程。此外,当您使用Python时,您需要使用Global Interpreter Lock,这会阻碍依赖大量并发线程的代码。
在Unix上,您可以考虑使用不同的进程而不是线程,或者查看其他异步处理方式(Twisted服务器框架有处理异步网络任务的有趣方法,如果您觉得真的很冒险,可以看看在stackless Python,一个完全不使用内核线程的延续框架。
答案 3 :(得分:2)
如果需要并发,可以考虑使用微线程。关于这个主题有一篇很好的文章here。优点是你不会创建占用资源并导致上下文切换的“真实”线程。当然,缺点是您没有利用多核技术。
如果您正在进行I / O,您可以考虑使用异步I / O.这可能是一个真正的编程难题,但它可以防止你让线程争夺CPU时间。不幸的是,我不知道在Python中有任何独立于平台的方法。
答案 4 :(得分:1)
线程确实有一些CPU和内存开销,但除非你产生数百或数千个,它通常不是那么重要。更重要的问题是,如果在并发线程之间共享任何可写数据结构,则线程使正确编程变得更加困难。请参阅文章The Problem with Threads以获得解释为何它们不是并发编程的良好抽象的原因。
答案 5 :(得分:1)
周围的优秀答案!我只是想补充一点,如果您决定使用线程池(如果您认为线程适合您的应用程序通常是可取的),那么建议您重用(并可能适应)现有的通用实现,例如Christopher Arndt's,而不是从头开始自己(这总是一项有益的工作,确保,但在使你正常工作和调试代码所需的时间方面效率较低; - )。