在Python中进行线程化

Ian*_*Ian 6 python multithreading

我是线程新手,并且想知道为各种任务(在服务器环境中)产生大量线程是否不好.与更线性的编程相比,线程占用更多的内存/ CPU吗?

ebo*_*ebo 18

如果要使用多个线程,则必须考虑多个事项:

  1. 您只能同时运行#processors线程.(明显)
  2. 在Python中,每个线程都是一个"内核线程",它通常需要非常少量的资源(默认情况下在linux上为8 mb堆栈)
  3. Python有一个全局解释器锁,这意味着只能处理一个python指令,而与处理器数量无关.但是,如果您的某个线程等待IO,则会释放此锁定.

我从中得出的结论:

  1. 如果您正在使用IO(Turbogears,Twisted)或正在使用正确编码的扩展模块(numpy),请使用线程.
  2. 如果要同时执行python代码,请使用进程(最简单的多进程模块)

  • +1:如果你的算法不是为并发而设计的,那么线程就没有用了.通常,多处理(通过简单的Linux管道)将为您提供可以利用的所有并发性.通过管道连接的许多小型流程非常高效且易于构建. (2认同)

Mic*_*rks 5

由于您是线程新手,因此还有其他值得注意的事项 - 我更倾向于将其视为值的并行范围.

对于任何给定对象的传统线性/顺序编程,您只有一个线程访问和更改一段数据.由于具有词法范围,这通常是安全的.具体而言,一个函数可以对变量的值进行操作,而不会影响全局值.如果您没有词法范围或不良的词法范围,那么在一个函数中更改名为"foo"的变量的值会影响另一个名为"foo"的变量.现在这种问题不太常见,但仍然很常见,可以提及.

使用线程,您可以以更微妙的方式处理相同的问题.虽然你仍然有词汇范围帮助你 - 因为一个函数内的局部值"X"独立于另一个函数中称为"X"的另一个本地值,数据结构是可变的这一事实是线程中错误的主要来源.

具体来说,如果函数传递了一个可变值,那么在线程环境中除非你已经注意,否则该函数不能保证该值不被其他任何东西改变.

这种共享状态是线程系统中大约90-99%的错误的来源,并且可能非常难以调试.因此,如果您要编写一个线程系统,您应该记住共享值的行进距离 - 即并行访问的范围.

为了限制bug,你可以使用一些已知可行的选项:

  1. 不使用共享状态 - 使用线程安全队列传递共享数据
  2. 在所有共享数据周围放置锁,并确保在整个代码中使用它.这可能比人们想象的要困难得多.问题来自于你"忘记"锁定一个物体 - 这对人们来说非常容易.
  3. 有一个对象 - 一个所有者 - 负责共享状态.允许客户端线程向其询问共享状态中值的副本,这些副本带有令牌.当他们想要更新共享状态时,他们会将消息以及他们拥有的令牌传递回单个对象.然后,所有者可以确定是否发生了更新冲突.

1最相当于unix管道.图3在逻辑上等同于版本控制,并且通常被称为软件事务存储器.

1和3是Kamaelia支持的并发模式,旨在消除由2级引起的错误.(披露,我运行Kamaelia项目)2不受支持,因为它依赖于"始终使一切正确".

无论你使用哪种方法来解决你的问题,牢记这个问题,以及处理它的方法,以及预先计划你打算如何处理它将为你节省下来的麻烦.


Yan*_*rtz 4

这取决于平台。

Windows 线程在创建时必须提交大约 1MB 的内存。拥有某种线程池比像疯子一样生成线程更好,以确保您永远不会分配超过固定数量的线程。此外,当您使用 Python 工作时,您会受到全局解释器锁的影响,这会阻碍依赖大量并发线程的代码。

在 Unix 上,您可以考虑使用不同的进程而不是线程,或者查看其他异步处理方式(Twisted 服务器框架有处理异步网络任务的有趣方法,如果您真的喜欢冒险,可以看看 stackless Python ,一个根本不真正使用内核线程的延续框架)。