杀死所有工人/线程ThreadPoolExecutor

时间:2018-03-22 00:25:19

标签: python multithreading python-3.6

过去一天我一直在努力解决当前的问题。

我有一个python脚本,它应该使用线程计数并根据每个线程执行请求。

每个线程都经过一个名为doit()的函数,该函数具有while函数。该循环只有在满足某个标准时才会中断,并且当它中断时,以下线程也会中断。

我想要实现的是,一旦这些线程/工作者中的一个从他们的请求获得状态代码200,所有工作者/线程就应该停止。我的问题是,即使符合标准,它也不会停止。

这是我的代码:

import threading
import requests
import sys
import urllib.parse
import concurrent.futures
import simplejson
from requests.auth import HTTPDigestAuth
from requests.packages import urllib3
from concurrent.futures import ThreadPoolExecutor

def doit(PINStart):
    PIN = PINStart
    while True:
        req1 = requests.post(url, data=json.dumps(data), headers=headers1, verify=False)
        if str(req1.status_code) == "200":
            print(str(PINs))
            c0 = req1.content
            j0 = simplejson.loads(c0)
            AuthUID = j0['UserId']
            print(UnAuthUID)
            AuthReqUser()
            #Kill all threads/workers if any of the threads get here.
            break
        elif(PIN > (PINStart + 99)):
              break
        else:
            PIN+=1

def main():
    threads = 100
    threads = int(threads)
    Calcu = 10000/threads
    NList = [0]
    for i in range(1,threads):
        ListAdd = i*Calcu
        if ListAdd == 10000:
            NList.append(int(ListAdd))
        else:
            NList.append(int(ListAdd)+1)

    with concurrent.futures.ThreadPoolExecutor(max_workers=threads) as executor:
        tGen = {executor.submit(doit, PinS): PinS for PinS in NList}
        for NLister in concurrent.futures.as_completed(tGen):
            PinS = tGen[NLister]



if __name__ == "__main__":
    main()

我明白为什么会这样。因为我只在其中一个线程中打破了while循环,所以其他99(我默认运行100个线程的代码)不会中断,直到它们完成计数(通过循环运行100次或获取状态)代码200)。

我最初做的是在代码顶部定义一个全局变量,而我在Counter< 10000,这意味着它将为所有工作程序运行循环,直到Counter大于10000.并且在循环内部它将增加全局变量。这样,当一个worker获得状态代码200时,我将Counter(我的全局变量)设置为例如15000(大于10000),所以其他所有工作者都停止运行循环100次。

这不起作用。当我将其添加到代码中时,所有线程立即停止,甚至不会在循环中运行一次。

以下是此解决方案的示例代码:

import threading
import requests
import sys
import urllib.parse
import concurrent.futures
import simplejson
from requests.auth import HTTPDigestAuth
from requests.packages import urllib3
from concurrent.futures import ThreadPoolExecutor
global Counter
def doit(PINStart):
    PIN = PINStart
    while Counter < 10000:
        req1 = requests.post(url, data=json.dumps(data), headers=headers1, verify=False)
        if str(req1.status_code) == "200":
            print(str(PINs))
            c0 = req1.content
            j0 = simplejson.loads(c0)
            AuthUID = j0['UserId']
            print(UnAuthUID)
            AuthReqUser()
            #Kill all threads/workers if any of the threads get here.
            Counter = 15000
            break
        elif(PIN > (PINStart + 99)):
            Counter = Counter+1
            break
        else:
            Counter = Counter+1
            PIN+=1

def main():
    threads = 100
    threads = int(threads)
    Calcu = 10000/threads
    NList = [0]
    for i in range(1,threads):
        ListAdd = i*Calcu
        if ListAdd == 10000:
            NList.append(int(ListAdd))
        else:
            NList.append(int(ListAdd)+1)

    with concurrent.futures.ThreadPoolExecutor(max_workers=threads) as executor:
        tGen = {executor.submit(doit, PinS): PinS for PinS in NList}
        for NLister in concurrent.futures.as_completed(tGen):
            PinS = tGen[NLister]



if __name__ == "__main__":
    main()

一旦我从我发出的一个请求中获取状态代码200,我是否可以杀死所有工作人员?

1 个答案:

答案 0 :(得分:0)

问题是你使用全局变量。

要在函数中使用全局变量,必须将global语句放在该函数中,而不是在顶层。因为你没有,Counter里面doit是一个局部变量。除非您有global(或nonlocal)声明,否则分配给函数中任何位置的任何变量都是本地变量。

第一次使用本地Counter时,就在while循环的顶部,在您为其分配任何内容之前。所以,它会立即提升UnboundLocalError

此异常将作为未来的结果传播回主线程​​。你会看到的,除了你从未真正评估过你的未来。你这样做:

   tGen = {executor.submit(doit, PinS): PinS for PinS in NList}
   for NLister in concurrent.futures.as_completed(tGen):
        PinS = tGen[NLister]

因此,您获得与您运行的函数相对应的PinS,但您不会查看结果或异常;你忽略它。因此,你没有看到你得到100个异常,其中任何一个都会告诉你实际上是错的。这相当于在非线程代码中只有except: pass。即使你不想出于某种原因在“生产”中检查你的期货结果,你肯定应该在调试问题时这样做。

无论如何,只需将global放在正确的位置,就可以修复错误。

但是,你至少还有两个问题。

首先,在线程之间共享全局变量而不同步它们是不安全的。在CPython中,感谢GIL,你永远不会因为它而受到段错误的影响,而且你经常完全逃脱它,但你经常不这样做。你可以错过计数,因为两个线程同时尝试Counter = Counter + 1,所以他们都将它从42增加到43.你可以在while Counter < 10000:检查中得到一个陈旧的值并通过循环额外的时间。

其次,在完成下载和处理完整请求之前,不要检查Counter。这可能需要几秒钟,甚至几分钟,具体取决于您的超时设置。并补充一点,你可能会在知道退出时间之前花费额外的时间来循环...