过去一天我一直在努力解决当前的问题。
我有一个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,我是否可以杀死所有工作人员?
答案 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
。这可能需要几秒钟,甚至几分钟,具体取决于您的超时设置。并补充一点,你可能会在知道退出时间之前花费额外的时间来循环...