[英]Killing all workers/threads ThreadPoolExecutor
在过去的一天里,我一直在努力解决当前的问题。
我有一个python脚本,应该使用线程计数并根据每个线程执行请求。
每个线程都通过一个名为doit()的函数,该函数具有while True函数。 此循环仅在满足特定条件时才会中断,并且在中断时,以下线程也会中断。
我要实现的是,一旦这些线程/工作程序之一从其请求中获取状态代码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 True循环,所以其他99个线程(默认情况下,我使用100个线程运行代码)直到它们完成计数(循环运行100次或获取状态)时才中断代码200)。
我最初的工作是在代码顶部定义一个全局变量,然后在Counter <10000时进行了更改,这意味着它将对所有工作程序运行循环,直到Counter大于10000。并且在循环内它将递增全局变量。 。 这样,当一个工作人员获得状态码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后如何杀死所有工作人员的任何想法?
问题是您没有使用全局变量。
要在函数中使用全局变量,必须将global
语句放在该函数中 ,而不是放在顶层。 因为没有,所以doit
内部的Counter
是一个局部变量。 您分配给函数中任何位置的任何变量都是本地变量,除非您具有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:
获得陈旧的值while Counter < 10000:
检查并遍历循环额外的时间。
其次,在完成下载和处理完整的请求之前,不要检查Counter
。 根据您的超时设置,这可能需要几秒钟,甚至几分钟。 并添加一个事实,您可能会在知道要退出的时候再经历一次循环……
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.