Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/279.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python多线程同步_Python_Multithreading - Fatal编程技术网

Python多线程同步

Python多线程同步,python,multithreading,Python,Multithreading,我正在使用多线程,并尝试使用线程。条件在线程之间同步。问题是这样的: do_something() with condition: set_flag() condition.notify() 我有一条主线。在某些情况下,它会这样做: if not is_flag_set(): with condition: condition.wait(120) 它这样做的原因是,它试图给后台线程一些机会,让它在向前移动之前执行do_something(): do_s

我正在使用多线程,并尝试使用
线程。条件
在线程之间同步。问题是这样的:

do_something()
with condition:
    set_flag()
    condition.notify()
我有一条主线。在某些情况下,它会这样做:

if not is_flag_set():
    with condition:
        condition.wait(120)
它这样做的原因是,它试图给后台线程一些机会,让它在向前移动之前执行
do_something()

do_something()
set_flag()
with condition:
    condition.notifyAll()
标志是主线程和后台线程都考虑的共享资源。当线程尝试访问标志时,我会添加锁。然而,我认为这里的方法并不能解决问题。主线程可以先检查标志,然后后台线程可以设置标志并执行
notifyAll
。这将导致主线程实际浪费120秒

我想要一种方法,它可以确保只有在后台线程的
dou_something()
未完成时,主线程才会等待后台线程


编辑:刚刚意识到我忘记了带
语句的

我认为你错过了
条件的要点
:你必须检查条件对象内部的条件谓词/变量,而不是外部的条件谓词/变量

condition.wait()的while点是它将等待,直到收到通知为止。它将以低廉的价格等待,不使用CPU电源,也不消耗电池;在接到通知之前,它什么也不做。因此,如果您正确地使用它们,它们会完全按照您的要求执行:“仅当来自后台线程的
do\u something()
未完成时,才等待后台线程。”

但你必须正确使用它们。在主线程上,执行以下操作:

with condition:
    condition.wait_for(is_flag_set)
    do_stuff()
然后,在后台线程上,您会这样通知它:

do_something()
with condition:
    set_flag()
    condition.notify()

为了简单起见,我删除了超时。如果要确保它等待后台线程执行
do_something()
,或2分钟,以较早者为准:

with condition:
    if condition.wait_for(is_flag_set, 120):
        do_stuff_after_flag_set()
    else:
        do_stuff_after_timeout()
现在,您可以保证只有在后台线程上完成了
dou something
之后,才会调用
dou stuff\u after\u flag\u set
,或者由于后台线程花费的时间太长,才会调用
dou stuff\u after\u timeout


如果要了解(已编辑)现有代码的问题,请执行以下操作:

if not is_flag_set():
    with condition:
        condition.wait(120)
您担心主线程会在设置条件之前检查标志。当然可以,;在对条件执行任何操作之前,请先输入
if
。这就是为什么您必须使用
wait_for
,或者在
循环
wait
时使用
,如中所示;这是确保在通知您已准备好检查标志时检查标志的唯一方法

另外,请注意,这里并没有真正同步任何内容。如果对
的调用是\u flag\u set
并且
set\u flag
未在
中发生,且条件为:
,则该标志在线程之间不同步。(在大多数平台上使用CPython,您几乎总能逃脱惩罚,但如果您寻找的是几乎总能逃脱惩罚的东西,而不是正确的东西,那么首先您真的不需要
条件


一些注意事项:

  • 如果没有Python3.2或更高版本,则只有
    等待
    ,而不是
    等待
    ,并且无法判断等待是否成功或超时。除了超时问题之外,
    c.wait\u for(设置了标志)
    基本上与
    相同,而不是设置标志():c.wait()
    。因此,您可以自己构建
    wait_
    (注意到的链接),或者您可以在PyPI上找到一个后端口

  • 如果你想知道为什么你需要这样做,维基百科的文章很好地解释了这个额外的复杂性所解决的问题。(如果您已经考虑了所有比赛条件,并且知道不需要
    条件
    ,请使用
    事件
    。)

  • 请注意,我使用了
    notify
    而不是
    notify\u all
    (或
    notifyAll
    ,这是
    notify\u all
    的另一个名称,但自Python 2.6以来一直被弃用)。如果只有一个服务员,你只需要通知一个服务员;隐藏起来更简单,也更清楚你的意图。(如果有人看到
    notify_all
    ,他们可能会认为您使用的是线程池,而您不是。)

  • 还请注意,我将
    do_stuff()
    放在锁内。这两种方式实际上都无关紧要,除非您要重置标志并在以后再次设置。但如果它真的这样做了,这将保护您免受“错过周期”错误的影响

  • 最后,你并不真的需要一个
    wait_for
    或者一个循环
    wait
    ;如果该标志在整个程序中只分配一次,并且该条件只通知一次,则在
    等待
    之后而不是在您尝试之前的
    if
    将具有相同的效果。(同样,使用
    事件
    或其他更简单的同步对象也是如此。)但最好是以安全的方式进行;然后,当你以后编辑一些看起来不相关的东西时,你不会意外地添加种族或死锁


我认为您忽略了
条件的要点:您必须检查条件对象内部的条件谓词/变量,而不是外部的条件谓词/变量

condition.wait()的while点是它将等待,直到收到通知为止。它将以低廉的价格等待,不使用CPU电源,也不消耗电池;在接到通知之前,它什么也不做。因此,如果您正确地使用它们,它们会完全按照您的要求执行:“仅当来自后台线程的
do\u something()
未完成时,才等待后台线程。”

但你必须正确使用它们。在主线程上,执行以下操作:

with condition:
    condition.wait_for(is_flag_set)
    do_stuff()
然后,在后台线程上,您会这样通知它:

do_something()
with condition:
    set_flag()
    condition.notify()

为了简单起见,我删除了超时。如果要确保它等待后台线程执行