Queue.task_done() 在完成一項工作之后,Queue.task_done()函數向任務已經完成的隊列發送一個信號
Queue.join() 實際上意味着等到隊列為空,再執行別的操作
如果線程里每從隊列里取一次,但沒有執行task_done(),則join無法判斷隊列到底有沒有結束,在最后執行個join()是等不到結果的,會一直掛起。
可以理解為,每task_done一次 就從隊列里刪掉一個元素,這樣在最后join的時候根據隊列長度是否為零來判斷隊列是否結束,從而執行主線程。
下面看個自己寫的例子:
下面這個例子,會在join()的地方無限掛起,因為join在等隊列清空,但是由於沒有task_done,它認為隊列還沒有清空,還在一直等。
class BdSpider(threading.Thread): """搜狗移動相關詞獲取爬蟲""" def __init__(self, waiting): super(BdSpider, self).__init__() self.waiting = waiting self.headers = { 'User-Agent': "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Mobile Safari/537.36" } def run(self): flag = True while flag: ipone = self.waiting.get() error = self.get_html(ipone) if error == -1: flag = False # self.waiting.task_done() def get_html(self, ipone,num_retries=3): global allipus global error_counter error_counter = 0 try: ip = {"http":"http://"+str(ipone) , "https":"http://"+str(ipone)} requests.get('https://m.sogou.com/', proxies=ip , timeout = 3 , headers = self.headers) except: error_counter += 1 if num_retries > 0: return self.get_html(ipone , num_retries - 1) else: if str(ipone) not in str(allipus): print("保留ip:" + str(ipone)) allipus.append(ipone) error_counter = 0 if error_counter > 50: return -1
#更新獲取ip def ipAction(ipsss): ipall = [] if ipsss: for iss in ipsss: if iss: ipall.append(iss) url = "http://api.ip.data5u.com/api/get.shtml?order=194469bc039df0eb7580e09541aa0624&num=20&carrier=0&protocol=2&an1=1&an2=2&an3=3&sp1=1&sp2=2&sp3=3&sort=1&system=1&distinct=0&rettype=1&seprator=%0A" for num in range(5): time.sleep(10) sss = requests.get(url) soup = BeautifulSoup(sss.text ,'html.parser') guoneiip = str(soup).split("\n") for ip in guoneiip: if ip: ipall.append(ip) wait_list = Queue() thread_num = 20 for keyip in ipall: if keyip: keyip = keyip.strip()#去除空格 wait_list.put(keyip)#往Queue添加 for i in range(thread_num): thread = BdSpider(wait_list) thread.setDaemon(True)#設置守護進程 thread.start() wait_list.join() return allipus allipus = []
傳入一個
Queue waiting當
self.waiting.task_done()此行注釋程序會一直卡死,無限掛起狀態。此時被認為線程沒結束,被 .join()。守護。主線程結束不了
原文參考http://www.vuln.cn/8610