简体   繁体   English

Python线程执行阻止了其他线程

[英]Python thread execution blocking other threads

Both threads work if accessed but when they are executed together halt_listener will monopolize the resources not allowing import_1 to execute. 如果两个线程都被访问,则它们都起作用,但是当它们一起执行时, halt_listener将垄断资源,从而不允许import_1执行。 The end goal is to have halt_listener listen for a kill message and then set a run variable to false. 最终目标是让halt_listener监听一条kill消息,然后将运行变量设置为false。 This has worked when I was sending a pipe to the halt_listener but I prefer a queue. 当我将管道发送到halt_listener时,此方法已奏效,但我更喜欢队列。

Here is my code: 这是我的代码:

import multiprocessing 
import time 
from threading import Thread

class test_imports:#Test classes remove 
      alive = {'import_1': True, 'import_2': True};

      def halt_listener(self, control_Queue, thread_Name, kill_command):
          while True:
              print ("Checking queue for kill")
              isAlive = control_queue.get()
              print ("isAlive", isAlive)
              if isAlive == kill_command:
                 print ("kill listener triggered")
                 self.alive[thread_Name] = False;
                 return

      def import_1(self, control_Queue, thread_Number):
          print ("Import_1 number %d started") % thread_Number
          halt = test_imports()
          t = Thread(target=halt.halt_listener, args=(control_Queue, 'import_1', 't1kill'))
          count = 0 
          t.run()
          global alive 
          run = test_imports.alive['import_1'];
          while run:
                print ("Thread type 1 number %d run count %d") % (thread_Number, count)
                count = count + 1
                print ("Test Import_1 ", run)
                run = self.alive['import_1'];
          print ("Killing thread type 1 number %d") % thread_Number 

Am I missing something? 我想念什么吗?

The problem is that you're calling t.run() . 问题是您正在调用t.run() run isn't a method that starts a thread; run不是启动线程的方法; run is the actual code that's meant to run on the thread. run是要在线程上run的实际代码。 By calling it directly, you're running it on your thread, and waiting for it to finish. 通过直接调用它,你运行它在你的线程,并等待它完成。

What you want is t.start() . 您想要的是t.start()

See the documentation on threading.Thread for details. 有关详细信息,请参见关于threading.Thread的文档。


While we're at it, there are a few other problems with your code. 在我们讨论过程中,您的代码还有其他一些问题。

First, you don't have a lock around self.alive . 首先,您没有对self.alive的锁定。 You can't change a value (except for a small number of automatically-self-synchronized types like Queue ) in one thread and access it in another without a lock. 您无法在一个线程中更改值(除了少数自动自我同步的类型,例如Queue ),而不能在没有锁的情况下访问另一个线程。 You will often get away with it, but "often" in a multithreaded program just means it won't fail until your big demonstration, and it will then take weeks to figure out how to reproduce before you can even begin fixing it… (In this case, a Condition might make more sense than a Lock, but either way, you need to synchronize on something .) 您通常会无所适从,但是“经常”在多线程程序中只是意味着它直到您的大型演示才会失败,然后您将需要数周的时间弄清楚如何进行复制,甚至可以开始对其进行修复……(在在这种情况下,“条件”可能比“锁定”更有意义,但是无论哪种方式,您都需要在某些事物上进行同步。)

Meanwhile, looping as fast as possible to poll self.alive['import_1'] is going to burn 100% CPU for no good reason. 同时,尽可能快地循环以轮询self.alive['import_1']self.alive['import_1']消耗100%的CPU。 There's almost always a better way to wait on something (eg, in this case, if you used a Condition for synchronization, you could also use it for waiting here); 几乎总是有一种更好的方法来等待某事(例如,在这种情况下,如果您使用条件进行同步,则也可以在这里等待它); in the rare cases when there isn't, you should at least sleep every time through the loop. 在极少数情况下,如果没有,至少每次循环时都应该sleep

alive is actually a class attribute rather than an instance attribute. alive实际上是一个类属性,而不是实例属性。 That's usually not what you want. 通常这不是您想要的。 In fact, you try to access both test_imports.alive and self.alive , but both of those will end up being the class attribute as long as you never assign to it, which makes it more confusing. 实际上,您尝试同时访问test_imports.aliveself.alive ,但是只要您从未分配它们,它们最终都将成为class属性,这会使它更加混乱。 And then, on top of that, you have a global with the same name, which is just a recipe for extreme confusion. 然后,最重要的是,您有一个具有相同名称的全局名称,这只是极度混乱的秘诀。

Also, this looks like Python 2 code, but you're using print as if it were a function in some cases—eg, print ("isAlive", isAlive) . 同样,这看起来像Python 2代码,但是您在某些情况下使用print好像它是一个函数,例如print ("isAlive", isAlive) This isn't going to do what you want—instead of printing something like isAlive command , it's going to print something like ('isAlive', 'command') , which is not very pretty. 这不会做您想要的事情,而不是打印类似isAlive command东西,而是打印类似('isAlive', 'command') ,这不是很漂亮。 And meanwhile, the extra parentheses in expressions like ("Import_1 number %d started") % thread_Number mean that someone has to read that over a few times to convince themselves that the parentheses aren't actually doing anything. 同时, ("Import_1 number %d started") % thread_Number等表达式中的多余括号表示某人必须多次阅读才能使自己确信括号实际上没有做任何事情。

Finally, why are you creating a separate test_imports instance to call halt_listener on? 最后,为什么要创建一个单独的test_imports实例来调用halt_listener Clearly the two methods are trying to communicate through attributes on self , but they're not going to do that if they're called on two different objects. 显然,这两种方法试图通过self属性进行通信,但是如果在两个不同的对象上调用它们,它们将不会这样做。 Why not just target=self.half_listener ? 为什么不只是target=self.half_listener

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM