Python 为什么我的多进程队列看起来不是线程安全的?

Python 为什么我的多进程队列看起来不是线程安全的?,python,multithreading,multiprocessing,message-queue,python-multiprocessing,Python,Multithreading,Multiprocessing,Message Queue,Python Multiprocessing,我正在构建一个运行另一个Python程序的看门狗计时器,如果它无法从任何线程中找到签入,则会关闭整个程序。这样,它最终将能够控制所需的通信端口。计时器的代码如下所示: from multiprocessing import Process, Queue from time import sleep from copy import deepcopy PATH_TO_FILE = r'.\test_program.py' WATCHDOG_TIMEOUT = 2 class Watchdog:

我正在构建一个运行另一个Python程序的看门狗计时器,如果它无法从任何线程中找到签入,则会关闭整个程序。这样,它最终将能够控制所需的通信端口。计时器的代码如下所示:

from multiprocessing import Process, Queue
from time import sleep
from copy import deepcopy

PATH_TO_FILE = r'.\test_program.py'
WATCHDOG_TIMEOUT = 2

class Watchdog:

    def __init__(self, filepath, timeout):
        self.filepath = filepath
        self.timeout = timeout
        self.threadIdQ = Queue()
        self.knownThreads = {}

    def start(self):
        threadIdQ = self.threadIdQ

        process = Process(target = self._executeFile)
        process.start()
        try:
            while True:
                unaccountedThreads = deepcopy(self.knownThreads)

                # Empty queue since last wake. Add new thread IDs to knownThreads, and account for all known thread IDs
                # in queue
                while not threadIdQ.empty():
                    threadId = threadIdQ.get()
                    if threadId in self.knownThreads:
                        unaccountedThreads.pop(threadId, None)
                    else:
                        print('New threadId < {} > discovered'.format(threadId))
                        self.knownThreads[threadId] = False

                # If there is a known thread that is unaccounted for, then it has either hung or crashed.
                # Shut everything down.
                if len(unaccountedThreads) > 0:
                    print('The following threads are unaccounted for:\n')
                    for threadId in unaccountedThreads:
                        print(threadId)
                    print('\nShutting down!!!')
                    break
                else:
                    print('No unaccounted threads...')

                sleep(self.timeout)

        # Account for any exceptions thrown in the watchdog timer itself
        except:
            process.terminate()
            raise

        process.terminate()


    def _executeFile(self):
        with open(self.filepath, 'r') as f:
            exec(f.read(), {'wdQueue' : self.threadIdQ})

if __name__ == '__main__':
    wd = Watchdog(PATH_TO_FILE, WATCHDOG_TIMEOUT)
    wd.start()
如您所见,我需要将线程放入queue.queue中,而一个单独的对象将queue.queue的输出缓慢地输入到多处理队列中。相反,如果我将线程直接放入多处理队列,或者在两次放入之间没有QToQ对象睡眠,则多处理队列将锁定,并且在看门狗端看起来总是空的

现在,由于多处理队列应该是线程和进程安全的,我只能假设我在实现中弄错了什么。我的解决方案似乎有效,但也感觉不够老套,我觉得我应该修复它


如果有必要的话,我正在使用Python 3.7.2。

我怀疑
test\u program.py
存在

我将最后几行更改为:

tq = threadQ
# tq = wdQueue    # option to send messages direct to WD

t1 = Thread(name='fastThread', target=fastThread, args=(tq,))
t2 = Thread(name='slowThread', target=slowThread, args=(tq,))
t3 = Thread(name='hangThread', target=hangThread, args=(tq,))

t1.start()
t2.start()
t3.start()
QToQ(wdQueue, threadQ)

print('Joining with threads...')
t1.join()
t2.join()
t3.join()

print('test_program exit')
join()
的调用意味着测试程序永远不会自行退出,因为没有任何线程退出

因此,
t3
挂起,看门狗程序检测到这一点,并检测到未解释的线程并停止测试程序


如果从上述程序中删除了
t3
,则其他两个线程的性能良好,并且看门狗程序允许测试程序无限期地继续运行。

我使用的是Python 3.6(
来自队列导入队列
),我不能让它失败。我可以通过“
wdQueue
或使用
QToQ
通过
Queue
直接发送ID,看门狗总是拾取
hangID
并关闭程序。虽然没有
hangThread
更新,但它总是在某个时候关闭。你的
除外
希望成为
最终的
。谢谢!加入线程似乎解决了这个问题,即使我没有创建QToQ,线程直接写入多处理队列。我仍然不明白为什么使用QToQ似乎可以解决这个问题,但我将在稍后进行调查;这显然是一个更好的解决方案。有趣的一点是:我尝试在watchdog timer循环中检查process.is_alive(),但它总是返回true,即使在bug发生时也是如此。然而,问题似乎仍然是进程正在退出,因为像while True:pass这样简单的东西似乎也解决了问题。您应该尝试不要进行繁忙的等待,例如
while True:pass
,而是使用一个合理的块,如:
t1.join()
。这将减少服务器上的cpu负载。
tq = threadQ
# tq = wdQueue    # option to send messages direct to WD

t1 = Thread(name='fastThread', target=fastThread, args=(tq,))
t2 = Thread(name='slowThread', target=slowThread, args=(tq,))
t3 = Thread(name='hangThread', target=hangThread, args=(tq,))

t1.start()
t2.start()
t3.start()
QToQ(wdQueue, threadQ)

print('Joining with threads...')
t1.join()
t2.join()
t3.join()

print('test_program exit')