我们将会看到一些在Python中使用线程的实例和如何避免线程之间的竞争。
你应当将下边的例子运行多次,以便可以注意到线程是不可预测的和线程每次运行出的不同结果。
声明:从这里开始忘掉你听到过的关于GIL的东西,因为GIL不会影响到我想要展示的东西。
示例1:
我们将要请求五个不同的url:
单线程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
import time import urllib2 def get_responses(): urls = [ 'http://www.google.com', 'http://www.amazon.com', 'http://www.ebay.com', 'http://www.alibaba.com', 'http://www.reddit.com' ] start = time.time() for url in urls: print url resp = urllib2.urlopen(url) print resp.getcode() print "Elapsed time: %s" % (time.time()-start) get_responses() |
输出是:
1 2 3 4 5 6 |
http://www.google.com 200 http://www.amazon.com 200 http://www.ebay.com 200 http://www.alibaba.com 200 http://www.reddit.com 200 Elapsed time: 3.0814409256 |
解释:
- url顺序的被请求
- 除非cpu从一个url获得了回应,否则不会去请求下一个url
- 网络请求会花费较长的时间,所以cpu在等待网络请求的返回时间内一直处于闲置状态。
多线程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
import urllib2 import time from threading import Thread class GetUrlThread(Thread): def __init__(self, url): self.url = url super(GetUrlThread, self).__init__() def run(self): resp = urllib2.urlopen(self.url) print self.url, resp.getcode() def get_responses(): urls = [ 'http://www.google.com', 'http://www.amazon.com', 'http://www.ebay.com', 'http://www.alibaba.com', 'http://www.reddit.com' ] start = time.time() threads = [] for url in urls: t = GetUrlThread(url) threads.append(t) t.start() for t in threads: t.join() print "Elapsed time: %s" % (time.time()-start) get_responses() |
输出:
1 2 3 4 5 6 |
http://www.reddit.com 200 http://www.google.com 200 http://www.amazon.com 200 http://www.alibaba.com 200 http://www.ebay.com 200 Elapsed time: 0.689890861511 |
解释:
- 意识到了程序在执行时间上的提升
- 我们写了一个多线程程序来减少cpu的等待时间,当我们在等待一个线程内的网络请求返回时,这时cpu可以切换到其他线程去进行其他线程内的网络请求。
- 我们期望一个线程处理一个url,所以实例化线程类的时候我们传了一个url。
- 线程运行意味着执行类里的
run()
方法。 - 无论如何我们想每个线程必须执行
run()
。 - 为每个url创建一个线程并且调用
start()
方法,这告诉了cpu可以执行线程中的run()
方法了。 - 我们希望所有的线程执行完毕的时候再计算花费的时间,所以调用了
join()
方法。 ݱ响到我想要展示的东西。示例1:
我们将要请求五个不同的url:
单线程
12345678910111213141516171819import timeimport urllib2def get_responses():urls = ['http://www.google.com','http://www.amazon.com','http://www.ebay.com','http://www.alibaba.com','http://www.reddit.com']start = time.time()for url in urls:print urlresp = urllib2.urlopen(url)print resp.getcode()print "Elapsed time: %s" % (time.time()-start)get_responses()输出是:
123456http://www.google.com 200http://www.amazon.com 200http://www.ebay.com 200http://www.alibaba.com 200http://www.reddit.com 200Elapsed time: 3.0814409256解释:
- url顺序的被请求
- 除非cpu从一个url获得了回应,否则不会去请求下一个url
- 网络请求会花费较长的时间,所以cpu在等待网络请求的返回时间内一直处于闲置状态。
多线程
1234567891011121314151617181920212223242526272829303132import urllib2import timefrom threading import Threadclass GetUrlThread(Thread):def __init__(self, url):self.url = urlsuper(GetUrlThread, self).__init__()def run(self):resp = urllib2.urlopen(self.url)print self.url, resp.getcode()def get_responses():urls = ['http://www.google.com','http://www.amazon.com','http://www.ebay.com','http://www.alibaba.com','http://www.reddit.com']start = time.time()threads = []for url in urls:t = GetUrlThread(url)threads.append(t)t.start()for t in threads:t.join()print "Elapsed time: %s" % (time.time()-start)get_responses()输出:
123456http://www.reddit.com 200http://www.google.com 200http://www.amazon.com 200http://www.alibaba.com 200http://www.ebay.com 200Elapsed time: 0.689890861511解释:
- 意识到了程序在执行时间上的提升
- 我们写了一个多线程程序来减少cpu的等待时间,当我们在等待一个线程内的网络请求返回时,这时cpu可以切换到其他线程去进行其他线程内的网络请求。
- 我们期望一个线程处理一个url,所以实例化线程类的时候我们传了一个url。
- 线程运行意味着执行类里的
run()
方法。 - 无论如何我们想每个线程必须执行
run()
。 - 为每个url创建一个线程并且调用
start()
方法,这告诉了cpu可以执行线程中的run()
方法了。 - 我们希望所有的线程执行完毕的时候再计算花费的时间,所以调用了
join()
方法。 v>