python中有两个处理多线程的模块thread和threading。其中thread提供了多线程底层支持的模块,以低级原始的发那个是来处理和控制线程,使用起来较为复杂;而threading基于thread进行包装,将线程操作对象化。

最基础的的多线程

我们先看一个最最基础的多线程例子

import threading
import time
class test(threading.Thread):
def __init__(self,name,delay):
threading.Thread.__init__(self)
self.name = name
self.delay = delay def run(self):
print "%s is running"%self.name
for x in range(self.delay):
time.sleep(1)
print "%s is saying hello %d"%(self.name,x) def main():
t1 = test('Thread 1',3)
t2 = test('Thread 2',2)
t1.start()
t2.start() if __name__ == '__main__':
main()
print "End of main"

输出结果如下:

Thread 1 is running
 End of mainThread 2 is running

Thread 1 is saying hello 0
Thread 2 is saying hello 0
Thread 1 is saying hello 1
Thread 2 is saying hello 1
Thread 1 is saying hello 2

可以看出Thread1 和Thread2基本上轮流执行的,这就是多线程的好处,否则如果顺序执行2个程序会需要2倍的时间。

start是对thread的run()的封装,在调用start()的时候,会执行run()函数。

如果把代码中的一段改成下面这样呢?

def main():
t1 = test('Thread 1',3)
t2 = test('Thread 2',2)
t1.start()
print "wait for thread1 end"
t1.join()
t2.start()

输出结果为:

wait for thread1 endThread 1 is running

Thread 1 is saying hello 0
Thread 1 is saying hello 1
Thread 1 is saying hello 2
End of mainThread 2 is running

Thread 2 is saying hello 0
Thread 2 is saying hello 1

从上面可以看出,调用了t1.join()后,t2会一直等到t1执行完毕才会开始执行。

使用Queue进行多线程编程

使用线程队列

如前所述,当多个线程需要共享数据或者资源的时候,可能会使得线程的使用变得复杂。线程模 块提供了许多同步原语,包括信号量、条件变量、事件和锁。当这些选项存在时,最佳实践是转而关注于使用队列。相比较而言,队列更容易处理,并且可以使得线 程编程更加安全,因为它们能够有效地传送单个线程对资源的所有访问,并支持更加清晰的、可读性更强的设计模式。

import threading
import time
import Queue
import urllib2
import os
class test(threading.Thread):
def __init__(self,queue):
threading.Thread.__init__(self)
self.queue = queue def run(self):
while 1:
url = self.queue.get()
print self.name+"begin download"+url+"..."
self.download(url)
self.queue.task_done()
print self.name+"download completed" def download(self,url):
urlHandle = urllib2.urlopen(url)
with open(os.path.basename(url)+".html","wb")as fp:
while 1:
contents=urlHandle.read(1024)
if not contents:
break
else:
fp.write(contents)
def main():
ulrs = ["http://wiki.python.org/moin/Webprograming",
"https://www.baidu.com",
"http://wiki.python.org/moin/Documendation"] q = Queue.Queue(5)
for each in ulrs:
q.put(each) for i in range(5):
t = test(q)
t.setDaemon(True)
t.start() q.join() if __name__ == '__main__':
main()

join()

保持阻塞状态,直到处理了队列中的所有项目为止。在将一个项目添加到该队列时,未完成的任务的总数就会增加。当使用者线程调用 task_done() 以表示检索了该项目、并完成了所有的工作时,那么未完成的任务的总数就会减少。当未完成的任务的总数减少到零时,join() 就会结束阻塞状态。

每个线程运行的时候就从队列里get一个url,这时候队列的长度就缩小1,然后完成的时候发送通知。直到队列为空的时候表示全部执行完毕。

调试的时候发现即使不要task_done()也可以得到一样的结果。但是主线程会一直阻塞着无法继续执行,所以task_done的任务是告诉主线程的当前任务完成了,并递减未完成的任务数,这样主线程才知道什么时候所有的任务都完成了,好继续执行。

使用线程池

可以自己实现一个线程池模块,也可以用已经存在的第三方线程池库,本文用的是后者,比较简单。

首先安装一个threadpool的库

pip install threadpool

然后用下面的代码完成和使用Queue一样的功能

import urllib2
import os
import threadpool def download(url):
urlHandle = urllib2.urlopen(url)
with open(os.path.basename(url)+".html","wb")as fp:
while 1:
contents=urlHandle.read(1024)
if not contents:
break
else:
fp.write(contents) def main():
ulrs = ["http://wiki.python.org/moin/Webprograming",
"https://www.baidu.com",
"http://wiki.python.org/moin/Documendation"]
thread_num=5
pool = threadpool.ThreadPool(thread_num)
requests = threadpool.makeRequests(download,ulrs)
print "put all request to thread pool"
for each in requests:
pool.putRequest(each)
pool.poll() # 处理任务队列中新的请求
pool.wait() # 阻塞用于等待所有执行结果
print "destroy all threads"
pool.dismissWorkers(thread_num,do_join=True) if __name__ == '__main__':
main()

最新文章

  1. AngularJs之六(服务)
  2. 使用stylelint对CSS/Sass做代码审查
  3. DbnBase64加密处理
  4. 如何挂自己的web项目(免费拥有自己的网站及域名)
  5. CentOS 7.2 安装 Docker 1.12.3 版
  6. 使用Apache Archiva搭建Maven Repository Server
  7. 全栈必备 Linux 基础
  8. Liquid基础语法
  9. 关于linux python vim的一些基础知识(很零散)
  10. IOS 改变导航栏返回按钮的标题
  11. 51nod1349 最大值
  12. javaWeb学习笔记
  13. 9、XAML名称空间详解
  14. C++中的虚函数总结
  15. ASP.ENT中上一篇和下一篇
  16. hdu4296 贪心
  17. ubuntu14.04下安装rubinius测试原生线程
  18. Eureka-Client(Golang实现)
  19. Cocos Creator cc.Button (脚本事件内容)
  20. android 7.0 调用系统相机崩溃的解决方案(非谷歌官方推荐)

热门文章

  1. vim-addon-manager【转】
  2. poj 1041(欧拉回路+输出字典序最小路径)
  3. Laravel5.1 模型 --软删除
  4. linux 学习笔记1
  5. 谈抽象1——无脑copy等于自杀
  6. 回溯法——n后问题
  7. 截取字符(pos,copy,Leftstr,MidStr,RightStr)以逗号为准把字符串拆分,判断字符串是否有数字、字母(大小写), 去掉字符串空格
  8. 学习 《UNIX网络编程》
  9. XShell安装(五)
  10. 将电脑中编写的app网页放到手机上访问