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_Python 3.x - Fatal编程技术网

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关于
队列的好建议
,几乎要用唯一的令牌来实现它。