Python 仅通过第一个到达函数的线程运行函数';他在叫什么
我有点被难住了。这是密码Python 仅通过第一个到达函数的线程运行函数';他在叫什么,python,multithreading,python-3.x,Python,Multithreading,Python 3.x,我有点被难住了。这是密码 def getIP(self,commandline): """ A thread that sets an IP using the method specified in commandline """ getter_process = subprocess.Popen(commandline,stdout=subprocess.PIPE) myip = getter_process.communicate()[0].dec
def getIP(self,commandline):
"""
A thread that sets an IP using the method specified in commandline
"""
getter_process = subprocess.Popen(commandline,stdout=subprocess.PIPE)
myip = getter_process.communicate()[0].decode(encoding="ascii", errors="ignore").replace("\n","")
print("getIP with ", commandline, " result:" , myip)
if isIP(myip):
self.lock1.acquire()
try:
GLib.idle_add(self.setIndicatingMenus,myip,self.hIndicator)
finally:
self.lock1.release()
print("debug2")
print("getIP end")
return False
def askIP(self,ind):
"""
Start subprocesses asking for external IP in separate threads
"""
print("askIP start")
#list of commandlines that are supposed to return IP as a result
IPgettingMethods = [
["dig", "+short", "myip.opendns.com", "@resolver1.opendns.com"],
["dig", "+short", "myip.opendns.com", "@resolver1.opendns.com"],
# and other command line commands I may want in separate threads
]
for i in IPgettingMethods:
th = Thread(target=self.getIP, args=(i,))
th.start()
return False
基本上,每当调用askIP
时,它都会启动几个执行IPgettingMethods
中指定的子进程的getIP
线程。这些子流程可能以不同的速度返回myip
值。此外,它们可能不会返回有效值(在这种情况下,isIP(myip)
将返回False
)。但是一个(或多个)线程最终将到达GLib.idle\u add(self.setIndicatingMenus、myip、self.hIndicator)
我的问题是:如何使GLib.idle\u add(self.setIndicatingMenus、myip、self.indicator)
在每次调用askIP
时只运行一次?换句话说,我怎样才能让第一个到达它的线程调用它,而让所有其他线程忽略它
也许我可以在“winner”线程调用GLib.idle\u add?后杀死其他线程。你应该使用一个全局变量作为保护:到达该执行点的第一个线程设置变量,其他线程在看到变量已设置时,跳过该代码:
def getIP(self,commandline):
"""
A thread that sets an IP using the method specified in commandline
"""
global guard
getter_process = subprocess.Popen(commandline,stdout=subprocess.PIPE)
myip = getter_process.communicate()[0].decode(encoding="ascii", errors="ignore").replace("\n","")
print("getIP with ", commandline, " result:" , myip)
if isIP(myip) and not guard:
self.lock1.acquire()
try:
GLib.idle_add(self.setIndicatingMenus,myip,self.hIndicator)
guard = True
finally:
self.lock1.release()
print("debug2")
print("getIP end")
return False
def askIP(self,ind):
"""
Start subprocesses asking for external IP in separate threads
"""
global guard
guard = False
print("askIP start")
#list of commandlines that are supposed to return IP as a result
IPgettingMethods = [
["dig", "+short", "myip.opendns.com", "@resolver1.opendns.com"],
["dig", "+short", "myip.opendns.com", "@resolver1.opendns.com"],
# and other command line commands I may want in separate threads
]
for i in IPgettingMethods:
th = Thread(target=self.getIP, args=(i,))
th.start()
return False
“手动”杀死线程几乎从来都不是一个好主意。让他们在函数结束时死去,通过设置防护来阻止他们工作。这听起来很适合使用--一种提交和控制多个作业的方式。在这里,您有许多助手线程,它们完成了调用子进程的后腿工作,还有一个主线程负责收集结果并决定如何处理它们。例如:
from concurrent.futures import ThreadPoolExecutor, as_completed
from time import sleep
from random import random
job_count = 10
def is_even(x):
return x % 2 == 0
def do_something(i):
"All odd jobs complete before even jobs"
if not is_even(i):
return i
sleep(0.1 + random())
return i
with ThreadPoolExecutor(max_workers=job_count) as executor:
successful_result = None
futures = [executor.submit(do_something, i) for i in range(job_count)]
for future in as_completed(futures):
result = future.result()
if is_even(result):
successful_result = result
break
print("the first successful result was:", successful_result)
适用于您的问题:
def getIP(self, commandline):
getter_process = subprocess.Popen(commandline, stdout=subprocess.PIPE)
myip = getter_process.communicate()[0].decode(encoding="ascii", errors="ignore").replace("\n","")
return myip if isIP(myIP) else None
def askIP(self,ind):
"""
Start subprocesses asking for external IP in separate threads
"""
print("askIP start")
#list of commandlines that are supposed to return IP as a result
IPgettingMethods = [
["dig", "+short", "myip.opendns.com", "@resolver1.opendns.com"],
["dig", "+short", "myip.opendns.com", "@resolver1.opendns.com"],
# and other command line commands I may want in separate threads
]
def get_ip_controller():
with ThreadPoolExecutor(len(IPgettingMethods)) as executor:
futures = [executor.submit(self.getIP, i) for i in IPgettingMethods]
for future in as_completed(futures):
ip = future.result()
if ip:
GLib.idle_add(self.setIndicatingMenus, ip, self.hIndicator)
break
Thread(target=get_ip_controller).start()
它可能会带来一场比赛,但它也可能按照你的意愿发挥作用。尝试将锁切换到
threading.Event
,如果未设置事件
,请将其设置并执行idle\u add
调用。如果设置了,则返回False。您也可以使用包含单个项目的队列来执行此操作。然后检查Queue.empty()
,如果没有,则执行Queue.get(false)
,这样你就不会阻塞,以防另一个线程在竞赛中击败你。@sberry关于队列的好建议
,几乎要用唯一的令牌来实现它。