python 多线程学习

来源:互联网 发布:淘宝宝贝下架后在哪里 编辑:程序博客网 时间:2024/06/05 16:08

以下面的爬虫程序为例,详细学习python多线程编程。
知识点:

守护进程:也叫Daemon进程, 运行在linux或unix一种后台进程。不依赖终端运行,运行过程不会被终端打断,信息不会在终端上被显示出来,周期性执行任务或者等待某些事件的发生,与系统共生死,在系统启动时守护进程运行于后台,当系统关闭时,该进程也结束。
守护线程:python中的守护线程类似于java中的守护线程,像守护进程一样,在后台执行某些任务,当全部的user用户任务执行完毕,守护线程也结束。比如说java虚拟机的垃圾回收线程。具体参考守护线程总结

import urllib2from threading import Thread,RLockfrom Queue import Queue  #Python中的Queue对象也提供了对线程同步的支持。使用Queue对象可以实现多个生产者和多个消费者形成的FIFO的队列。import time'''f = Fetcher(threads=10) #设定下载线程数为10for url in urls:    f.push(url)  #把所有url推入下载队列while f.taskleft(): #若还有未完成下载的线程    content = f.pop()  #从下载完成队列中取出结果    do_with(content) # 处理content内容'''#在threading模块中,定义两种类型的琐:threading.Lock和threading.RLock。class Fetcher:    def __init__(self,threads):# 创建完对象后调用,对当前对象的实例的一些初始化,无返回值        self.opener = urllib2.build_opener(urllib2.HTTPHandler)#build_opener默认添加几个处理器,但提供快捷的方法来添加或更新默认处理器。        self.lock =RLock() #线程锁,同一线程不能多次调用acquire,死锁        self.q_req = Queue() #任务队列,实现线程同步        self.q_ans = Queue() #完成队列        self.threads = threads        for i in range(threads):            t = Thread(target=self.threadget)#threadget函数作为参数            t.setDaemon(True)#主线程A启动了子线程B,调用b.setDaemaon(True),则主线程结束时,会把子线程B也杀死,必须在start()之前调用,默认false.            t.start()        self.running = 0'''当我们获得一个url正在使用一个opener(一个urllib2.OpenerDirector的实例),正常情况下默认是urlopen,但是我们可以创建opener,并通过handler处理该url。见[opener学习链接](http://blog.csdn.net/hshl1214/article/details/45853863)'''    def __del__(self): #解构时需等待两个队列完成        time.sleep(0.5)        self.q_req.join()        self.q_ans.join()    def taskleft(self):        return self.q_req.qsize()+self.q_ans.qsize()+self.running    def push(self,req):        self.q_req.put(req)#调用队列对象的put()方法在队尾插入一个项目。put()有两个参数,第一个item为必需的,为插入项目的值;第二个block为可选参数,默认为1。如果队列当前为空且block为1,put()方法就使调用线程暂停,直到空出一个数据单元。如果block为0,put方法将引发Full异常。    def pop(self):        return self.q_ans.get()    def threadget(self):      while True:            req = self.q_req.get()#调用队列对象的get()方法从队头删除并返回一个项目。可选参数为block,默认为True。如果队列为空且block为True,get()就使调用线程暂停,直至有项目可用。如果队列为空且block为False,队列将引发Empty异常。            self.lock.acquire()            #with self.lock: #要保证该操作的原子性,进入critical area            self.running += 1            self.lock.release()            try:                ans = self.opener.open(req).read()            except Exception, what:                ans = ''                print what            self.q_ans.put((req,ans))            #with self.lock:            self.lock.acquire()            self.running -= 1            self.lock.release()            self.q_req.task_done()#在完成一项工作之后,Queue.task_done() 函数向任务已经完成的队列发送一个信号            time.sleep(0.1) # don't spamif __name__ == "__main__":    #访问限制的问题见http://www.pythonclub.org/python-network-application/observer-spider#%E5%A4%9A%E7%BA%BF%E7%A8%8B%E5%B9%B6%E5%8F%91%E6%8A%93%E5%8F%96    headers = {    'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'    }    req = urllib2.Request(    url ="http://blog.csdn.net/zhaoyl03/article/details/8631645" ,    headers = headers    )    links = []    links.append("http://china.cnr.cn/yaowen/20151205/t20151205_520695743.shtml")    links.append("http://www.cankaoxiaoxi.com/roll/roll10/2015/1205/1017899.shtml")    links.append("http://baijia.baidu.com/?tn=topic&topicid=xd61e4WS")    links.append(req)    f = Fetcher(threads=6)    for url in links:        f.push(url)    while f.taskleft():        url,content = f.pop()        print url,len(content)
0 0
原创粉丝点击