单线程演示:python
1.线程就比如<进程线程.形象的说明进程和线程的区别?>中所说的工厂的工人,一个工人干一个任务叫作单线程
git
2.以下单个线程去访问4个不一样的URL,要求返回URL地址和返回码
github
#!/usr/bin/env python # -*- coding: utf-8 -*- """ # # Authors: limanman # OsChina: http://my.oschina.net/pydevops/ # Purpose: # """ import time import urllib2 def get_response(url_list): """Get url resp code. :param url_list: url list :return: """ sta_time = time.time() for cur_url in url_list: print cur_url, resp = urllib2.urlopen(cur_url) print resp.getcode() print 'cost time: %s' % (time.time()-sta_time) if __name__ == '__main__': url_list = [ 'https://www.baidu.com/', 'https://github.com/', 'http://www.aliyun.com/', 'https://www.dnspod.cn/', ] # 调用执行 get_response(url_list)
https://www.baidu.com/ 200 https://github.com/ 200 http://www.aliyun.com/ 200 https://www.dnspod.cn/ 200 cost time: 7.49797701836
说明:如上4个URL被顺序请求,除非CPU从一个URL得到了回应,不然不会去请求下一个URL,网络请求会花费较长时间,因此CPU在等待网络请求的返回时间内会一直处于闲置状态安全
多线程演示:网络
1.线程就比如<进程线程.形象的说明进程和线程的区别?>中所说的工厂的工人,多个工人干一个任务叫作多线程
多线程
2.以下多个线程去访问4个不一样的URL,要求返回URL地址和返回码app
#!/usr/bin/env python # -*- coding: utf-8 -*- """ # # Authors: limanman # OsChina: http://my.oschina.net/pydevops/ # Purpose: # """ import time import urllib2 import threading class MultThread(threading.Thread): def __init__(self, url): self.url = url super(MultThread, self).__init__() def run(self): print self.url, resp = urllib2.urlopen(self.url, data=None, timeout=3) print resp.getcode() def get_response(url_list): """Get resp with mulit threads. :param url_list: url list :return: """ # 建立url_list长度个线程 sta_time = time.time() thread_list = [] for cur_url in url_list: cur_thread = MultThread(cur_url) thread_list.append(cur_thread) # 通知CPU能够执行MultThread下面的run方法 cur_thread.start() # 保证全部线程执行完毕后再执行print,不然会先执行print而后再回头继续执行线程run方法 for cur_thread in thread_list: cur_thread.join() print 'cost time: %s' % (time.time()-sta_time) if __name__ == '__main__': url_list = [ 'https://www.baidu.com/', 'https://github.com/', 'http://www.aliyun.com/', 'https://www.dnspod.cn/', ] # 调用 get_response(url_list)
https://www.baidu.com/ https://github.com/ https://www.dnspod.cn/http://www.aliyun.com/ 200 200 200 200 cost time: 1.33794403076
说明:从执行时间上面已经明显感受有性能上提高,如上是一个多线程减小CPU等待时间,在等待一个线程内的网络请求返回时,CPU能够切换到其它线程去进行其它线程内的网络请求,因此你会发现打印的格式是先把全部的url打印出来,而后等待返回码,返回一个打印一个,咱们指望一个线程处理一个url,固然也能够一个线程处理多个url,因此实例化线程类咱们传入一个url,线程运行意味着执行类里的run()方法,性能
因此为每一个url建立一个线程并调用start()方法,告诉CPU能够执行线程中的run()方法了,咱们但愿全部的线程都执行完毕后再计算执行时间,因此咱们对每一个线程调用join()方法,它会通知主线程等待这个线程结束后,才会执行下一条指令,也就是print那句,须要注意的是CPU可能不会在调用start()后立刻执行run()方法,没法肯定run()在不一样线程间的执行顺序,对于单独的一个线程能够保证顺序执行,由于线程内的url会依次被请求并返回结果ui
全局变量线程安全问题:url
1.在<进程线程.形象的说明进程和线程的区别?>中说,车间的空间是工人们共享的,好比许多房间里是每一个工人均可以进出的,这就象征一个进程的内存空间是共享的,每一个线程均可以使用这些共享内存
2.在<进程线程.形象的说明进程和线程的区别?>中说,每一个房间的大小不一样,有些房间只能容纳一我的,好比厕所,里面有人的时候其余人不能进,这表明一个线程使用某些共享内存时,其它线程必须等待它结束,才能使用这一起内存
#!/usr/bin/env python # -*- coding: utf-8 -*- """ # # Authors: limanman # OsChina: http://my.oschina.net/pydevops/ # Purpose: # """ import time import threading class MultThread(threading.Thread): def __init__(self): super(MultThread, self).__init__() def run(self): global global_num currentnum = global_num print 'thread - %s currentnum - %s' % (self.name, currentnum) global_num = currentnum + 1 if __name__ == '__main__': # 全局变量 global_num = 0 thread_list = [] # 开启50个线程 for _ in xrange(50): cur_thread = MultThread() thread_list.append(cur_thread) cur_thread.start() for cur_thread in thread_list: cur_thread.join() print print 'global_num modify 50 times, should become 50.' print 'after 50 times modify, global_num is %s.' % (global_num)
thread - Thread-1 currentnum - 0 thread - Thread-2 currentnum - 1 thread - Thread-3 currentnum - 2 thread - Thread-4 currentnum - 3 thread - Thread-5 currentnum - 4 thread - Thread-6 currentnum - 5 thread - Thread-7 currentnum - 6 thread - Thread-8 currentnum - 7 thread - Thread-9 currentnum - 8thread - Thread-10 currentnum - 8 thread - Thread-11 currentnum - 9 thread - Thread-12 currentnum - 10 thread - Thread-13 currentnum - 11 thread - Thread-14 currentnum - 9 thread - Thread-15 currentnum - 10 thread - Thread-16 currentnum - 11 thread - Thread-17 currentnum - 12 thread - Thread-18 currentnum - 13 thread - Thread-19 currentnum - 14 thread - Thread-20 currentnum - 15 thread - Thread-21 currentnum - 16 thread - Thread-22 currentnum - 17 thread - Thread-23 currentnum - 18 thread - Thread-24 currentnum - 19 thread - Thread-25 currentnum - 20 thread - Thread-26 currentnum - 21thread - Thread-27 currentnum - 21 thread - Thread-28 currentnum - 22 thread - Thread-29 currentnum - 23 thread - Thread-30 currentnum - 24 thread - Thread-31 currentnum - 25 thread - Thread-32 currentnum - 26 thread - Thread-33 currentnum - 27 thread - Thread-34 currentnum - 28 thread - Thread-35 currentnum - 29 thread - Thread-36 currentnum - 30 thread - Thread-37 currentnum - 31 thread - Thread-38 currentnum - 32 thread - Thread-39 currentnum - 33 thread - Thread-40 currentnum - 34 thread - Thread-41 currentnum - 35 thread - Thread-42 currentnum - 36 thread - Thread-43 currentnum - 37 thread - Thread-44 currentnum - 38 thread - Thread-45 currentnum - 39 thread - Thread-46 currentnum - 40 thread - Thread-47 currentnum - 41 thread - Thread-48 currentnum - 42 thread - Thread-49 currentnum - 43 thread - Thread-50 currentnum - 44 global_num modify 50 times, should become 50. after 50 times modify, global_num is 45.
说明:有一个全局变量,全部的线程都想修改它,全部的线程应该在这个全局变量的基础上加1,有50个线程,最后这个数值应该变为50,为何没有到50?当global_num是8的时候,Thread-10读取了global_num,这个时刻cpu将控制权给了另外一个线程Thread-10,Thread-10读取到的也是8,Thread-9和Thread-10都把global_num加到9,可是咱们指望的是Thread-9和Thread-10两个线程使global_num+2变为10,也就是Thread-11为10,在这里有了资源竞争,相同的状况也会发生在其它线程之间,因此出现了最后的结果小于50的状况
解决资源竞争:
1.在<进程线程.形象的说明进程和线程的区别?>中说一个防止他进入的简单方法,就是门口加一把锁,先到的人锁上门,后到的人看到上锁,就在门口排队,等锁打开再进去,这就叫"互斥锁",防止多个线程同时读写某一块内存区域
#!/usr/bin/env python # -*- coding: utf-8 -*- """ # # Authors: limanman # OsChina: http://my.oschina.net/pydevops/ # Purpose: # """ import time import threading class MultThread(threading.Thread): def __init__(self, thread_lock): super(MultThread, self).__init__() self.thread_lock = thread_lock def run(self): global global_num # 获取一把锁 self.thread_lock.acquire() currentnum = global_num print 'thread - %s currentnum - %s' % (self.name, currentnum) global_num = currentnum + 1 # 释放这把锁 self.thread_lock.release() if __name__ == '__main__': # 全局变量 global_num = 0 # 互斥锁 lock = threading.Lock() thread_list = [] # 开启50个线程 for _ in xrange(50): cur_thread = MultThread(lock) thread_list.append(cur_thread) cur_thread.start() # 等待全部线程结束再执行下面的指令 for cur_thread in thread_list: cur_thread.join() print print 'global_num modify 50 times, should become 50.' print 'after 50 times modify, global_num is %s.' % (global_num)
thread - Thread-1 currentnum - 0 thread - Thread-2 currentnum - 1 thread - Thread-3 currentnum - 2 thread - Thread-4 currentnum - 3 thread - Thread-5 currentnum - 4 thread - Thread-6 currentnum - 5 thread - Thread-7 currentnum - 6 thread - Thread-8 currentnum - 7 thread - Thread-9 currentnum - 8 thread - Thread-10 currentnum - 9 thread - Thread-11 currentnum - 10 thread - Thread-12 currentnum - 11 thread - Thread-13 currentnum - 12 thread - Thread-14 currentnum - 13 thread - Thread-15 currentnum - 14 thread - Thread-16 currentnum - 15 thread - Thread-17 currentnum - 16 thread - Thread-18 currentnum - 17 thread - Thread-19 currentnum - 18 thread - Thread-20 currentnum - 19 thread - Thread-21 currentnum - 20 thread - Thread-22 currentnum - 21 thread - Thread-23 currentnum - 22 thread - Thread-24 currentnum - 23 thread - Thread-25 currentnum - 24 thread - Thread-26 currentnum - 25 thread - Thread-27 currentnum - 26 thread - Thread-28 currentnum - 27 thread - Thread-29 currentnum - 28 thread - Thread-30 currentnum - 29 thread - Thread-31 currentnum - 30 thread - Thread-32 currentnum - 31 thread - Thread-33 currentnum - 32 thread - Thread-34 currentnum - 33 thread - Thread-35 currentnum - 34 thread - Thread-36 currentnum - 35 thread - Thread-37 currentnum - 36 thread - Thread-38 currentnum - 37 thread - Thread-39 currentnum - 38 thread - Thread-40 currentnum - 39 thread - Thread-41 currentnum - 40 thread - Thread-42 currentnum - 41 thread - Thread-43 currentnum - 42 thread - Thread-44 currentnum - 43 thread - Thread-45 currentnum - 44 thread - Thread-46 currentnum - 45 thread - Thread-47 currentnum - 46 thread - Thread-48 currentnum - 47 thread - Thread-49 currentnum - 48 thread - Thread-50 currentnum - 49 global_num modify 50 times, should become 50. after 50 times modify, global_num is 50.
说明:Lock用来防止竞争条件,达到咱们预想的结果,若是在执行前thread-1得到了锁,其它线程在t1释放Lock以前,不会执行相同的操做,咱们想要肯定的是一旦Thread-1已经读取了global_num,直到完成了修改global_num,其它线程才能够读取和修改global_num
线程切换输出打断:
#!/usr/bin/env python # -*- coding: utf-8 -*- """ # # Authors: limanman # OsChina: http://my.oschina.net/pydevops/ # Purpose: # """ import time import threading class MultThread(threading.Thread): def __init__(self): super(MultThread, self).__init__() def run(self): self.entries = [] for i in xrange(10): # 强制CPU切换到其它线程 time.sleep(0.01) self.entries.append(i) # 打印会乱掉,可是也说明一个问题线程之间变量是相互独立的 print self.entries if __name__ == '__main__': thread_list = [] for _ in xrange(5): cur_thread = MultThread() thread_list.append(cur_thread) cur_thread.start()
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [0[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] , 1, 2, 3, 4, 5, 6, 7, 8, 9]
说明:上面用了一个time.sleep()来让一个线程挂起,强制切换到其它线程,可是并无和咱们指望同样打印正确结果,当一个线程正在打印时,CPU切换到另外一个线程,因此产生了不正确的结果,咱们须要保证print语句的原子操做,防止打印时被其它线程打断
保证线程原子操做:
#!/usr/bin/env python # -*- coding: utf-8 -*- """ # # Authors: limanman # OsChina: http://my.oschina.net/pydevops/ # Purpose: # """ import time import threading class MultThread(threading.Thread): def __init__(self, thread_lock): self.thread_lock = thread_lock super(MultThread, self).__init__() def run(self): self.entries = [] for i in xrange(10): # 强制CPU切换到其它线程 time.sleep(0.01) self.entries.append(i) # 打印会乱掉,可是也说明一个问题线程之间变量是相互独立的 self.thread_lock.acquire() print self.entries self.thread_lock.release() if __name__ == '__main__': # 互斥锁 lock = threading.Lock() thread_list = [] for _ in xrange(5): cur_thread = MultThread(lock) thread_list.append(cur_thread) cur_thread.start()
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
说明:此次咱们看到了正确结果,同时也说明了一个问题,一个线程不能够修改其它线程内部的变量(全局变量除外)
强制线程退出:
#!/usr/bin/env python # -*- coding: utf-8 -*- """ # # Authors: limanman # OsChina: http://my.oschina.net/pydevops/ # Purpose: # """ import time import threading class MultThread(threading.Thread): def __init__(self, thread_lock): self.thread_lock = thread_lock super(MultThread, self).__init__() def run(self): self.entries = [] for i in xrange(10): # 强制CPU切换到其它线程 time.sleep(0.01) self.entries.append(i) # 打印会乱掉,可是也说明一个问题线程之间变量是相互独立的 self.thread_lock.acquire() print self.entries self.thread_lock.release() if __name__ == '__main__': # 互斥锁 lock = threading.Lock() thread_list = [] for _ in xrange(5): cur_thread = MultThread(lock) thread_list.append(cur_thread) # 将主线程设置为守护线程,主线程结束后,无论子线程是否完成都一并和主线程退出 cur_thread.setDaemon(True) cur_thread.start() # 当前线程数若是不等于1,也就是除了守护线程还有其它线程在运行 while threading.activeCount() != 1: # 强制切换到守护线程外的其余线程运行 time.sleep(0.01) print 'found notice: all thread is finished.'
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] found notice: all thread is finished.
说明: 能够看出Thread-[1-5]的内容打印都没有打印出来,cur_thread.setDaemon(True)的操做将父线程设置为了守护线程,根据setDaemon()方法的含义,守护线程由于不会像join()那样等待子线程结束后执行下面的语句,因此守护线程会先执行print 'found notice: all thread is finished.'而后就结束了,全部子线程也就结束了,可是为了实现join()的效果,因此在上面能够加一个判断,判断包含守护线程在内的线程数是否等于1,若是等于1则表示全部的线程已经所有结束.
容许指定线程数更改数据:
1.在<进程线程.形象的说明进程和线程的区别?>说有些房间能够容纳n我的,好比厨房,也就是说,若是人数大于n,多出来的人只能在外面等着,这比如某些内存区域,只能供给固定数目的线程使用
2.在<进程线程.形象的说明进程和线程的区别?>说这时的解决办法,就是在门口挂n把锁,进去的人就取一把钥匙,出来的就把钥匙挂回原处,后来的人发现钥匙架为空,就知道必须门前排队等着,这种作法叫"信号量",用来保证多个线程不会相互冲突
#!/usr/bin/env python # -*- coding: utf-8 -*- """ # # Authors: limanman # OsChina: http://my.oschina.net/pydevops/ # Purpose: # """ import time import pprint import threading class MultThread(threading.Thread): def __init__(self, thread_semaphore): super(MultThread, self).__init__() self.thread_semaphore = thread_semaphore def run(self): # 获取锁 self.thread_semaphore.acquire() # 等待1秒,开始第二波 print 'run the thread %s' % (self.name) time.sleep(2) # 释放锁 self.thread_semaphore.release() if __name__ == '__main__': # 建立一个信号量对象,只容许同时5个线程运行,其余的线程只有其中有线程结束才能运行 semaphore = threading.BoundedSemaphore(5) # 建立100个线程,可是每次只容许5个线程同时容许 for _ in xrange(10): MultThread(semaphore).start()