多线程中的 Queue队列中join()与task_done() ,

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
posted @ 2018-06-19 15:03  自说自话唉  阅读(7302)  评论(1编辑  收藏  举报