gpt4 book ai didi

Python threading.Condition.notify_all() 不触发下一个线程

转载 作者:太空宇宙 更新时间:2023-11-03 20:30:22 25 4
gpt4 key购买 nike

我正在尝试解决这个 LeetCode 问题,Print Zero Even Odd :

enter image description here enter image description here

我尝试使用 threading.Condition 执行以下解决方案对象:

import threading
from typing import Callable, Optional


class ZeroEvenOdd:
def __init__(self, n: int):
self.n = n
self.i = 0
self.last_printed: Optional[int] = None
self.condition = threading.Condition()

def zero(self, printNumber: Callable[[int], None]) -> None:
with self.condition:
self.condition.wait_for(lambda: self.last_printed is None or self.last_printed > 0)
if self.done:
return
printNumber(0)
self.last_printed = 0
self.i += 1
self.condition.notify_all()

def even(self, printNumber: Callable[[int], None]) -> None:
with self.condition:
self.condition.wait_for(lambda: self.last_printed == 0 and self.i % 2 == 0)
if self.done:
return
self._print_and_notify()

def odd(self, printNumber: Callable[[int], None]) -> None:
with self.condition:
self.condition.wait_for(lambda: self.last_printed == 0 and self.i % 2 == 1)
if self.done:
return
self._print_and_notify()

def _print_and_notify(self) -> None:
printNumber(self.i)
self.last_printed = self.i
self.condition.notify_all()

@property
def done(self) -> bool:
if self.last_printed is not None and self.last_printed >= self.n:
self.condition.release()
self.condition.notify_all()
return True
return False


def printNumber(x: int) -> None:
print(x)


zero_even_odd = ZeroEvenOdd(n=5)
threadA = threading.Thread(target=zero_even_odd.zero, args=(printNumber,))
threadB = threading.Thread(target=zero_even_odd.even, args=(printNumber,))
threadC = threading.Thread(target=zero_even_odd.odd, args=(printNumber,))


if __name__ == "__main__":
threadA.start()
threadB.start()
threadC.start()

但是,当我运行它时,我发现它打印 0,然后打印 1,然后无限期挂起:

> python print_zero_even_odd.py
0
1
^CException ignored in: <module 'threading' from '/usr/local/Cellar/python/3.7.4/Frameworks/Python.framework/Versions/3.7/lib/python3.7/threading.py'>
Traceback (most recent call last):
File "/usr/local/Cellar/python/3.7.4/Frameworks/Python.framework/Versions/3.7/lib/python3.7/threading.py", line 1308, in _shutdown
lock.acquire()
KeyboardInterrupt

我有点困惑为什么在第一次调用 odd() 后,zero() 不再被调用。毕竟,在 odd() 中打印数字 1 后,self.last_printed 被设置为 1,这应触发 zero() 方法的 wait_for() 条件,self.last_printed > 0

知道为什么这个程序没有按预期工作吗?

最佳答案

正如 Sraw 所指出的,我的代码中没有循环,因此没有理由期望再次调用 zero() 。我最终使用 threading.Lock 对象以不同的方式解决了这个问题:

import threading
from typing import Callable, Optional


class ZeroEvenOdd:
def __init__(self, n: int):
self.n = n
self.i = 0

self.lock_zero = threading.Lock()
self.lock_odd = threading.Lock()
self.lock_even = threading.Lock()

self.lock_odd.acquire()
self.lock_even.acquire()

def zero(self, printNumber: Callable[[int], None]) -> None:
for _ in range(self.n):
self.lock_zero.acquire()
printNumber(0)

if self.i % 2 == 0:
self.lock_odd.release()
else:
self.lock_even.release()

def even(self, printNumber: Callable[[int], None]) -> None:
for i in range(2, self.n + 1, 2):
self.lock_even.acquire()
printNumber(i)
self.i = i
self.lock_zero.release()

def odd(self, printNumber: Callable[[int], None]) -> None:
for i in range(1, self.n + 1, 2):
self.lock_odd.acquire()
printNumber(i)
self.i = i
self.lock_zero.release()


def printNumber(x: int) -> None:
print(x)


zero_even_odd = ZeroEvenOdd(n=5)
threadA = threading.Thread(target=zero_even_odd.zero, args=(printNumber,))
threadB = threading.Thread(target=zero_even_odd.even, args=(printNumber,))
threadC = threading.Thread(target=zero_even_odd.odd, args=(printNumber,))


if __name__ == "__main__":
threadA.start()
threadB.start()
threadC.start()

这将打印所需的输出:

> python print_zero_even_odd.py
0
1
0
2
0
3
0
4
0
5

并以相当快速且节省内存的方式解决 LeetCode 问题:

enter image description here

关于Python threading.Condition.notify_all() 不触发下一个线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57550973/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com