只通过第一个到达它调用的线程来运行函数

2024-09-26 22:54:48 发布

您现在位置:Python中文网/ 问答频道 /正文

我有点被难住了。这是密码。你知道吗

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时,它都会启动几个getIP线程,这些线程执行IPgettingMethods中指定的子进程。这些子进程可能以不同的速度返回myip值。而且,它们可能不会返回有效值(在这种情况下,isIP(myip)将返回False)。但是一个(或多个)线程最终将到达GLib.idle_add(self.setIndicatingMenus,myip,self.hIndicator)。你知道吗

我的问题是:如何使每次调用askIPGLib.idle_add(self.setIndicatingMenus,myip,self.hIndicator)只运行一次?换言之,我怎样才能只让最先到达它的线程调用它,而让所有其他线程忽略它?你知道吗

也许我可以在“winner”线程调用GLib.idle_add之后杀死其他线程?你知道吗


Tags: inselfipcomadd线程commandlineprint
2条回答

您应该使用全局变量作为保护:到达该执行点的第一个线程将设置该变量,其他线程在看到已设置该变量时,跳过该代码段:

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()

相关问题 更多 >

    热门问题