我有一个程序,一旦达到某个阈值,就使用线程启动另一个线程。现在第二个线程正在多次启动。我实施了一个锁,但我认为我做得不对。
for i in range(max_threads):
t1 = Thread(target=grab_queue)
t1.start()
<_>在grab_queue中,我有:
...
rows.append(resultJson)
if len(rows.value()) >= 250:
with Lock():
row_thread = Thread(target=insert_rows, kwargs={'rows': rows.value()})
row_thread.start()
rows.reset()
启动另一个线程来处理行列表。我想确保只要它遇到if条件,其他线程就不会运行,以确保不会启动处理行列表的额外线程。
答案 0 :(得分:3)
您的锁占据了代码的错误部分。在检查行大小和重置行的代码部分之间存在竞争条件。鉴于在大小检查之后仅对进行锁定,两个线程可以很容易地确定数组已经变得太大,然后只有锁定才会启动序列化重置数组。 &#34;序列化&#34;在这种情况下意味着任务仍然会执行两次,每个线程执行一次,但它会连续发生而不是并行发生。
正确的代码可能如下所示:
rows.append(resultJson)
with grow_lock:
if len(rows.value()) >= 250:
row_thread = Thread(target=insert_rows, kwargs={'rows': rows.value()})
row_thread.start()
rows.reset()
问题中显示的代码还有另一个问题:如果Lock()
引用threading.Lock
,它会在每个调用和每个线程中创建并锁定一个新锁!锁保护线程之间共享的资源,并且为了执行该功能,锁必须自己共享。要解决此问题,请将锁实例化一次并将其传递给线程的目标函数。
退一步,您的代码实现了一个自定义线程池。做到这一点并覆盖所有角落案例需要大量的工作,测试和调试。有专门为此目的的生产测试模块,例如Python附带的multiprocessing
模块(支持进程和线程池),在重新实现其功能之前熟悉它们是个好主意。例如,请参阅this article以获取基于multiprocessing
的线程池的可访问介绍。