python如何停止子线程,python杀死子进程

  python如何停止子线程,python杀死子进程

  3358blog.solrex.org/articles/python-thread-cancel.html Python不支持杀死子线程。2009年02月09日昨天,我给我的casnet程序增加了一个新功能。其中一个功能是自动断开重连,本来是单线程程序。增加这个功能需要后台有一个线程定时查询当前状态,如果断开会自动重新连接。所以我遇到了一个如何设计这个守护线程的问题。

  我最初的想法是,后台线程在运行查询后会休眠一段时间,然后再运行查询。但我马上遇到了一个问题:主程序退出时,后台线程还在运行,主窗口无法退出。

  使用其他库时,比如POSIX的pthread,可以使用ptread_cancel(tid)来结束主线程中的子线程。但是,Python的线程库不支持这一点。原因是我们不要强求一个线程结束,这样会带来很多隐患。我们应该让线自己结束。所以在Python中,推荐的方法是在子线程中循环判断一个标志位,在主线程中改变标志位。当子线程读取标志位改变时,它自己结束。

  导入线程

  classX(线程。线程):

  def__init__(self):

  threading.Thread.__init__(self)

  self.flag=1

  defrun(自身):

  whileself.flag==1:

  睡眠(300)

  .

  如果直接用这个方法,那么我之前的设计就有问题了。因为线程会被睡眠阻塞一段时间,所以只能在睡眠的间隙读取标志位。这样,主线程需要等待当前睡眠结束,子线程才能退出,然后整个程序才能退出。这种做法是行不通的。你不能指望用户点击“关闭窗口”并等待数百秒后退出程序。

  当然,你也可以使用系统命令kill来杀死整个进程。但问题是这样做既不雅观,也不能保证代码与不同系统的兼容性。

  我们得换个思路,从原来的后台流程设计开始。常规执行不一定要用睡眠。也可以像crontab一样判断当前时间是否能被某个值整除,但这并不能保证任务在某个时间间隔内只执行一次,因为除数的精度和任务的执行时间都不好把握。或者使用timer,但是timer会带来更多的线程,增加复杂度。

  最后我决定用方法解决定时抓取Feedbuner图标的问题。在线程中保存上次查询时间,比较当前时间与上次查询时间的差值,如果大于某个值,则查询并更新保存的时间。

  defrun(自身):

  self.last=time.time()

  whileself.flag==1:

  Now=time.time()

  ifNow - self.last 300

  self.last=现在

  .

  这样可以保证子线程在标志改变后尽快退出,任务在指定的时间间隔内只能运行一次。但网友earthengine哥指出,这种方法并不合适。代码中没有睡眠,就变成了忙循环,会造成CPU利用率高的问题。只要在循环中间加一个sleep(0~1)就能大大降低CPU占用率,关闭程序时一秒内的延迟一般用户都能接受。

  defrun(自身):

  self.last=time.time()

  whileself.flag==1:

  睡眠(1)

  Now=time.time()

  ifNow - self.last 300

  self.last=现在

  .

  经过进一步的思考,虽然本文中的后台线程从功能角度看似乎不必考虑太多的同步问题,但最终的退出进程可以看作是一个线程同步进程。因此,可以采用线程同步的思想来设计后台线程:正常工作时,后台线程等待超时,超时后再执行工作;退出时,主线程向后台线程发送信号。因为后台线程正在等待超时,所以它在收到信号后终止退出。这样,当用户完成程序时,就不需要等待睡眠的到来。

  导入线程

  classX(线程。线程):

  def__init__(self):

  threading.Thread.__init__(self)

  self.flag=1

  self.cond=线程。条件()

  defrun(自身):

  自我cond.acquire()

  自我条件等待(300)

  whileself.flag==1:

  .

  自我调节释放()

  自我cond.acquire()

  自我条件等待(300)

  .

  x.flag=0

  第二次采集()

  第二次通知()

  x .第二次发布()

  最后,非常感谢earthengine兄弟的精彩评论。我弟弟受益匪浅。

  Solrex Yang 10条评论编程用火狐插件控制网瘾。Python 2.610注释尽量不要用Py2exe。在ptpython 2.6中,使用子进程生成子进程,可以杀死子进程。

  Popen.kill()

  杀死了孩子。在Posix OSs上,该函数将SIGKILL发送给孩子。在Windows上,kill()是terminate()的别名。

  2.6版新增。

  2009年8月30日回复Solrex Yang@earthengine

  嗯,其实我学Python是打野拳,所以对线程没有系统的了解,经常以教程或者一些网上资料作为快速了解的渠道。

  用线程代替线程也是如此。其实我对线程类了解不多。

  现在好像螺纹更方便了。有空的时候考虑一下线程和线程的优缺点。

  2009年2月20日,我回复了earthengine。我以为这是最简单的解决办法,谁知道还有更简单的。

  http://www.python.org/doc/2.5.2/lib/thread-objects.html

  直接在线程对象上使用join()方法可以让一个线程等待另一个线程退出。此方法支持超时。超时后在目标线程上使用isAlive()方法,可以知道那个线程是否已经退出运行。结合这两种方法,我们可以取消所有额外的同步变量和标志来实现要求(算法没有改变,等待同步变量改为加入,检查标志改为isAlive)。

  2009年2月18日回复NjuBeepython有SemaphoreObjects

  能实现wait和wake_up的都可以。

  2009年2月11日回复earthengine。其实有一个更简单的方法,不需要定时器。我不了解Python和它的同步机制,但是大部分语言的同步机制都包含了带超时的等待。如果Python支持的话,那么你的工作线程可以一直等待同步信号灯超时。如果你在等待信号,因为定时器被取消了,那它一定是来自主线程的,所以你可以退出。如果是加班,那就该工作了。当你做完的时候等待下一个信号。可以按照自己的Now-self.last算法设置超时,这样就可以不用定时器实现需求。

  09年2月11日回复zz的好分析,挺好的。

  我之前折腾过Pxpython,也遇到过类似的问题。

  2009年2月10日回复Solrex Yang@earthengine

  所以每次结束后你都要重置计时器?

  让我想想。

  2009年2月10日回复像earthengine这样的代码很不好。变成了一个没有睡眠的“忙碌”循环,会消耗大量CPU时间做无用的事情。甚至加个睡眠(0)就好多了。

  如果让我来设计,我会推荐使用定时器结合同步信号的方法。工作线程正常时,被同步信号灯阻断。每当定时器被激活时,它就向等待的作业发送这个信号来激活工作线程。线程被激活后,首先检查退出标志。能退出就退出吧。否则,做一个作业,然后释放信号灯,等待下一次另一个线程激活它。当主线程要退出时,首先设置退出标志,然后激活工作线程,平静地结束它的操作。

  事实上,引入一个像上面描述的那样简单的额外线程没什么大不了的。如果把相关代码都封装在一个类里,一两页就搞定了,简单的逻辑验证也不费力。

  2009年2月10日回复www.python.org/doc/2.5.2/lib/condition-objects.html http://号地球工程

  参考Python的线程库,最合适的同步对象应该是条件变量。但是它的wait方法,虽然超时了,但是分不清是超时了还是激活了。所以仍然需要一个标志来通知工作线程这个信息。

  2009年2月11日回复Solrex Yang@earthengine

  这个方法很好。非常感谢大家的评论。

  2009年2月12日回复

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: