Python(多线程threading模块)
day27
参考:http://www.cnblogs.com/yuanchenqi/articles/5733873.html
CPU像一本书,你不阅读的时候,你室友马上阅读,你准备阅读的时候,你室友记下他当时页码,等下次你不读的时候开始读。
多个线程竞争执行。
进程:A process can have one or many threads.一个进程有多个线程。
一个线程就是一堆指令集合。
线程和进程是同样的东西。
线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。
- import time
- import threading
- begin = time.time()
- def foo(n):
- print('foo%s'%n)
- time.sleep(1)
- def bar(n):
- print('bar%s'%n)
- time.sleep(2)
- # foo()
- # bar()
- # end = time.time()
- #并发,两个线程竞争执行
- t1 = threading.Thread(target = foo, args =(1,) )
- t2 = threading.Thread(target = bar, args =(2,) )
- t1.start()
- t2.start()
- t1.join()#t1,t2执行完再往下执行
- t2.join()
- #t1,t2同时执行
- end = time.time()
- print(end - begin)
- 并发,两个线程竞争执行
执行结果:
- foo1
- bar2
- 2.002244710922241
- Process finished with exit code 0
IO密集型任务函数(以上为IO密集型)计算效率会被提高,可用多线程
计算密集型任务函数(以下为计算密集型)改成C语言
- import time
- import threading
- begin = time.time()
- def add(n):
- sum = 0
- for i in range(n):
- sum += i
- print(sum)
- # add(50000000)
- # add(80000000)
- #并发,两个线程竞争执行
- t1 = threading.Thread(target = add, args =(50000000,) )
- t2 = threading.Thread(target = add, args =(80000000,) )
- t1.start()
- t2.start()
- t1.join()#t1,t2执行完再往下执行
- t2.join()
- end = time.time()
- print(end - begin)
计算密集型中用并发计算效率并没有提高。
计算效率并没有提高。
GIL
In CPython, due to the Global Interpreter Lock, only one thread can execute Python code at once.
在同一时刻,只能有一个线程。
使之有多个进程就可以解决(如果三个线程无法同时进行,那么把它们分到三个进程里面去,用于解决GIL问题,实现并发)。
线程与进程的区别:
- Threads share the address space of the process that created it; processes have their own address space.
- Threads have direct access to the data segment of its process; processes have their own copy of the data segment of the parent process.
- Threads can directly communicate with other threads of its process; processes must use interprocess communication to communicate with sibling processes.
- New threads are easily created; new processes require duplication of the parent process.
- Threads can exercise considerable control over threads of the same process; processes can only exercise control over child processes.
- Changes to the main thread (cancellation, priority change, etc.) may affect the behavior of the other threads of the process; changes to the parent process does not affect child processes.
threading_test.py
- import threading
- from time import ctime,sleep
- import time
- def music(func):
- for i in range(2):
- print ("Begin listening to %s. %s" %(func,ctime()))
- sleep(1)
- print("end listening %s"%ctime())
- def move(func):
- for i in range(2):
- print ("Begin watching at the %s! %s" %(func,ctime()))
- sleep(5)
- print('end watching %s'%ctime())
- threads = []
- t1 = threading.Thread(target=music,args=('七里香',))
- threads.append(t1)
- t2 = threading.Thread(target=move,args=('阿甘正传',))
- threads.append(t2)
- if __name__ == '__main__':
- for t in threads:#线程加到了列表中
- # t.setDaemon(True)
- t.start()
- # t.join()
- # t1.join()
- #t2.join()########考虑这三种join位置下的结果?
- print ("all over %s" %ctime())
- #一共执行10秒
一共只执行10秒,因为是同时执行,看哪个时间长。2*5s
执行结果:
- Begin listening to 七里香. Fri Nov 2 16:43:09 2018
- all over Fri Nov 2 16:43:09 2018
- Begin watching at the 阿甘正传! Fri Nov 2 16:43:09 2018
- end listening Fri Nov 2 16:43:10 2018
- Begin listening to 七里香. Fri Nov 2 16:43:10 2018
- end listening Fri Nov 2 16:43:11 2018
- end watching Fri Nov 2 16:43:14 2018
- Begin watching at the 阿甘正传! Fri Nov 2 16:43:14 2018
- end watching Fri Nov 2 16:43:20 2018
- Process finished with exit code 0
join
- import threading
- from time import ctime,sleep
- import time
- def music(func):
- for i in range(2):
- print ("Begin listening to %s. %s" %(func,ctime()))
- sleep(2)
- print("end listening %s"%ctime())
- def move(func):
- for i in range(2):
- print ("Begin watching at the %s! %s" %(func,ctime()))
- sleep(3)
- print('end watching %s'%ctime())
- threads = []
- t1 = threading.Thread(target=music,args=('七里香',))
- threads.append(t1)
- t2 = threading.Thread(target=move,args=('阿甘正传',))
- threads.append(t2)
- if __name__ == '__main__':
- for t in threads:#线程加到了列表中
- # t.setDaemon(True)
- t.start()
- #t.join() #变成了串行 t1已经执行完了,但是t2阻塞了,其中t为t2
- t1.join() #all over在第四秒就会被打印,因为t1四秒执行完,不再阻塞,而t2还在执行
- #t2.join()########考虑这三种join位置下的结果?
- print ("all over %s" %ctime())
- #一共执行6秒
t1.join,t1执行完才能到下一步,所以4秒后才能print ("all over %s" %ctime())
t2.join,t2执行结束才能到下一步,所以6秒后才能print ("all over %s" %ctime())
如果将t.join()放到for循环中,即和串行一样先执行t1,再执行t2。
setDeamon
- import threading
- from time import ctime,sleep
- import time
- def music(func):
- for i in range(2):
- print ("Begin listening to %s. %s" %(func,ctime()))
- sleep(2)
- print("end listening %s"%ctime())
- def move(func):
- for i in range(2):
- print ("Begin watching at the %s! %s" %(func,ctime()))
- sleep(3)
- print('end watching %s'%ctime())
- threads = []
- t1 = threading.Thread(target=music,args=('七里香',))
- threads.append(t1)
- t2 = threading.Thread(target=move,args=('阿甘正传',))
- threads.append(t2)
- if __name__ == '__main__':
- t2.setDaemon(True)
- for t in threads:#线程加到了列表中
- #t.setDaemon(True)
- t.start()
- print ("all over %s" %ctime())
- #主线程只会等待没设定的子线程t1,t2被设定setDaemon
- #t1已经执行完(4s),但是t2还没执行完,和主线程一起退出
- 32 #主线程只会等待没设定的子线程t1,t2被设定setDaemon
- 33 #t1已经执行完(4s),但是t2还没执行完,和主线程一起退出
- 执行结果:
- Begin listening to 七里香. Fri Nov 2 17:33:29 2018
- Begin watching at the 阿甘正传! Fri Nov 2 17:33:29 2018
- all over Fri Nov 2 17:33:29 2018
- end listening Fri Nov 2 17:33:31 2018
- Begin listening to 七里香. Fri Nov 2 17:33:31 2018
- end watching Fri Nov 2 17:33:32 2018
- Begin watching at the 阿甘正传! Fri Nov 2 17:33:32 2018
- end listening Fri Nov 2 17:33:33 2018
- Process finished with exit code 0
4秒就结束。
- print属于主线程!
- 继承式调用
- import threading
- import time
- class MyThread(threading.Thread):#继承
- def __init__(self, num):
- threading.Thread.__init__(self)
- self.num = num
- def run(self): # 定义每个线程要运行的函数
- print("running on number:%s" % self.num)
- time.sleep(3)
- if __name__ == '__main__':
- t1 = MyThread(1)
- t2 = MyThread(2)
- t1.start()
- t2.start()
同步锁
- import time
- import threading
- def addNum():
- global num #在每个线程中都获取这个全局变量
- temp = num
- time.sleep(0.0001)#在前一次还没执行完,就开始减1
- num =temp-1 #对此公共变量进行-1操作
- num = 100 #设定一个共享变量
- thread_list = []
- r = threading.Lock()#同步锁
- for i in range(100):
- t = threading.Thread(target=addNum)
- t.start()
- thread_list.append(t)
- for t in thread_list: #等待所有线程执行完毕
- t.join()
- print('final num:', num )#有join所有执行完再输出
执行结果:
- final num: 47
- Process finished with exit code 0
最终结果不是0的原因:由于有sleep的原因,100个减一操作几乎同时进行,前一次还在sleep没进行减法运算,全局变量就被后一次线程进行减法运算。
正常情况:100-1=99,99-1=98........1-1 = 0。
有sleep:100-1=99(还没减),全局变量100被拿走,进行下一线程的运算100-1=99,造成最后结果不为0;
解决方法:同步锁,使数据运算部分变成了串行。
- import time
- import threading
- def addNum():
- global num #在每个线程中都获取这个全局变量
- #num -= 1
- r.acquire()#同步锁,又变成串行
- temp = num
- #print('--get num:',num )
- time.sleep(0.0001)#在前一次还没执行完,就开始减1
- num =temp-1 #对此公共变量进行-1操作
- r.release()
- #只是将以上的部分变成了串行
- print('ok')
- #将不是数据的部分内容不放到锁中,100个线程同时拿到ok,这部分将不是串行,而是并发
- num = 100 #设定一个共享变量
- thread_list = []
- r = threading.Lock()#同步锁
- for i in range(100):
- t = threading.Thread(target=addNum)
- t.start()
- thread_list.append(t)
- for t in thread_list: #等待所有线程执行完毕
- t.join()
- print('final num:', num )#有join所有执
锁中的部分变成了串行,只有运行结束才进入下一线程。
但是锁外面的部分print('ok')还是并发的,100个线程同时拿到ok。
死锁和递归锁
在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁,因为系统判断这部分资源都正在使用,所有这两个线程在无外力作用下将一直等待下去。
- import threading,time
- class myThread(threading.Thread):
- def doA(self):
- lockA.acquire()
- print(self.name,"gotlockA",time.ctime())
- time.sleep(3)#以上部分被A锁住
- lockB.acquire()#下面的也锁住
- print(self.name,"gotlockB",time.ctime())
- lockB.release()#释放后,执行doB
- lockA.release()
- def doB(self):
- #在此过程中,第二个线程进入,因为A,B已经被释放
- lockB.acquire()#有锁,正常输出,由于第二个进入,所以A(第二个线程),B(第一个线程)几乎同时获取
- #但是之后第一个线程想要获取A锁的时候,A锁已经被第二个线程占着,造成死锁.
- print(self.name,"gotlockB",time.ctime())
- time.sleep(2)
- lockA.acquire()
- print(self.name,"gotlockA",time.ctime())#没有被打印,反而第二个线程的被打印了
- lockA.release()
- lockB.release()
- def run(self):
- self.doA()
- self.doB()
- if __name__=="__main__":
- lockA=threading.Lock()#两个锁
- lockB=threading.Lock()
- #lock = threading.RLock()#该锁可以多次获取,多次acquire和release
- threads=[]
- for i in range(5):#5个线程
- threads.append(myThread())
- for t in threads:
- t.start()
- for t in threads:
- t.join()#等待线程结束,后面再讲。
执行结果:
- Thread-1 gotlockA Sat Nov 3 13:40:48 2018
- Thread-1 gotlockB Sat Nov 3 13:40:51 2018
- Thread-1 gotlockB Sat Nov 3 13:40:51 2018
- Thread-2 gotlockA Sat Nov 3 13:40:51 2018
以上程序卡住不能运行,doA运行完锁A锁B都释放,准备运行doB,休眠2秒后,获取锁A,此时由于线程锁都被释放,可以进入其他线程,如进入线程二,同时也获取锁A,两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁。
解决方法:
- import threading,time
- class myThread(threading.Thread):
- def doA(self):
- lock.acquire()
- print(self.name,"gotlockA",time.ctime())
- time.sleep(3)#以上部分被A锁住
- lock.acquire()#下面的也锁住
- print(self.name,"gotlockB",time.ctime())
- lock.release()#释放后,执行doB
- lock.release()
- def doB(self):
- #在此过程中,第二个线程进入,因为A,B已经被释放
- lock.acquire()#有锁,正常输出,由于第二个进入,所以A(第二个线程),B(第一个线程)几乎同时获取
- #但是之后第一个线程想要获取A锁的时候,A锁已经被第二个线程占着,造成死锁.
- print(self.name,"gotlockB",time.ctime())
- time.sleep(2)
- lock.acquire()
- print(self.name,"gotlockA",time.ctime())#没有被打印,反而第二个线程的被打印了
- lock.release()
- lock.release()
- def run(self):
- self.doA()
- self.doB()
- if __name__=="__main__":
- # lockA=threading.Lock()#两个锁
- # lockB=threading.Lock()
- lock = threading.RLock()#该锁可以多次获取,多次acquire和release
- threads=[]
- for i in range(5):#5个线程
- threads.append(myThread())
- for t in threads:
- t.start()
- for t in threads:
- t.join()#等待线程结束,后
lock = threading.RLock(),该锁可以重用,只用lock。不用lockA,lockB。
执行结果:
- Thread-1 gotlockA Sat Nov 3 13:48:04 2018
- Thread-1 gotlockB Sat Nov 3 13:48:07 2018
- Thread-1 gotlockB Sat Nov 3 13:48:07 2018
- Thread-1 gotlockA Sat Nov 3 13:48:09 2018
- Thread-3 gotlockA Sat Nov 3 13:48:09 2018
- Thread-3 gotlockB Sat Nov 3 13:48:12 2018
- Thread-4 gotlockA Sat Nov 3 13:48:12 2018
- Thread-4 gotlockB Sat Nov 3 13:48:15 2018
- Thread-4 gotlockB Sat Nov 3 13:48:15 2018
- Thread-4 gotlockA Sat Nov 3 13:48:17 2018
- Thread-2 gotlockA Sat Nov 3 13:48:17 2018
- Thread-2 gotlockB Sat Nov 3 13:48:20 2018
- Thread-2 gotlockB Sat Nov 3 13:48:20 2018
- Thread-2 gotlockA Sat Nov 3 13:48:22 2018
- Thread-5 gotlockA Sat Nov 3 13:48:22 2018
- Thread-5 gotlockB Sat Nov 3 13:48:25 2018
- Thread-3 gotlockB Sat Nov 3 13:48:25 2018
- Thread-3 gotlockA Sat Nov 3 13:48:27 2018
- Thread-5 gotlockB Sat Nov 3 13:48:27 2018
- Thread-5 gotlockA Sat Nov 3 13:48:29 2018
信号量(Semaphore)
信号量用来控制线程并发数的,BoundedSemaphore或Semaphore管理一个内置的计数 器,每当调用acquire()时-1,调用release()时+1。
计数器不能小于0,当计数器为 0时,acquire()将阻塞线程至同步锁定状态,直到其他线程调用release()。(类似于停车位的概念)
BoundedSemaphore与Semaphore的唯一区别在于前者将在调用release()时检查计数 器的值是否超过了计数器的初始值,如果超过了将抛出一个异常。
- import threading,time
- class myThread(threading.Thread):
- def run(self):
- if semaphore.acquire():
- print(self.name)
- time.sleep(3)
- semaphore.release()
- if __name__=="__main__":
- semaphore=threading.Semaphore(5)
- thrs=[]
- for i in range(23):
- thrs.append(myThread())
- for t in thrs:
- t.start()
执行结果:
- Thread-1
- Thread-2
- Thread-3
- Thread-4
- Thread-5
- Thread-6
- Thread-7
- Thread-8
- Thread-9
- Thread-10
- Thread-11
- Thread-12
- Thread-13
- Thread-14
- Thread-15
- Thread-16
- Thread-17
- Thread-18
- Thread-19
- Thread-20
- Thread-21
- Thread-22
- Thread-23
- Process finished with exit code 0
一次同时输出五个,最后一次输出三个。
条件变量同步(Condition)
线程间通信的作用
- import threading,time
- from random import randint
- class Producer(threading.Thread):
- def run(self):
- global L#一屉
- while True:
- val=randint(0,100)
- print('生产者',self.name,":Append"+str(val),L)
- if lock_con.acquire():#锁 ,与lock_con.acquire()一样
- L.append(val)#做包子,从后面加
- lock_con.notify()#通知wait,激活wait
- lock_con.release()
- time.sleep(3)
- class Consumer(threading.Thread):
- def run(self):
- global L
- while True:
- lock_con.acquire()
- if len(L)==0:#没包子
- lock_con.wait()#wait阻塞
- print('消费者',self.name,":Delete"+str(L[0]),L)
- del L[0]#从前面吃
- lock_con.release()
- time.sleep(0.1)
- if __name__=="__main__":
- L=[]
- lock_con=threading.Condition()#条件变量的锁
- threads=[]
- for i in range(5):#启动五个人在做包子,5个线程
- threads.append(Producer())
- threads.append(Consumer())#
- for t in threads:
- t.start()
- for t in threads:
- t.join()
当一屉中有包子的时候,notify激活waiting,添加包子,和吃包子时有线程锁。
同步条件(Event)
- import threading,time
- class Boss(threading.Thread):
- def run(self):
- print("BOSS:今晚大家都要加班到22:00。")
- event.isSet() or event.set()#set()设为true
- time.sleep(5)
- print("BOSS:<22:00>可以下班了。")
- event.isSet() or event.set()
- class Worker(threading.Thread):
- def run(self):
- event.wait()#等待老板决定,阻塞
- print("Worker:哎……命苦啊!")
- #event.clear() # 标志位 False 等老板说可以下班, 设为true
- time.sleep(1)
- event.clear()#标志位 False 等老板说可以下班, 设为true
- event.wait()#等老板说别的 ,设为true后
- print("Worker:OhYeah!") #print Oh,Yeah
- if __name__=="__main__":
- event=threading.Event()
- threads=[]
- for i in range(5):#五个worker
- threads.append(Worker())
- threads.append(Boss())#一个老板
- for t in threads:
- t.start()
- for t in threads:
- t.join()
boss说完后,5个worker马上能有反应。boss输出后,even.set(),标志位变为True,worker中的event.wait()才能停止阻塞。之后还需将标志位设为False,即event.clear()。
再次等待boss说完话后even.set()将标志位变为True,worker再次发言。
执行结果:
- BOSS:今晚大家都要加班到22:00。
- Worker:哎……命苦啊!
- Worker:哎……命苦啊!
- Worker:哎……命苦啊!
- Worker:哎……命苦啊!
- Worker:哎……命苦啊!
- BOSS:<22:00>可以下班了。
- Worker:OhYeah!
- Worker:OhYeah!
- Worker:OhYeah!
- Worker:OhYeah!
- Worker:OhYeah!
- Process finished with exit code 0
Python(多线程threading模块)的更多相关文章
- 再看python多线程------threading模块
现在把关于多线程的能想到的需要注意的点记录一下: 关于threading模块: 1.关于 传参问题 如果调用的子线程函数需要传参,要在参数后面加一个“,”否则会抛参数异常的错误. 如下: for i ...
- python中threading模块详解(一)
python中threading模块详解(一) 来源 http://blog.chinaunix.net/uid-27571599-id-3484048.html threading提供了一个比thr ...
- python多线程threading.Lock锁用法实例
本文实例讲述了python多线程threading.Lock锁的用法实例,分享给大家供大家参考.具体分析如下: python的锁可以独立提取出来 mutex = threading.Lock() #锁 ...
- Python:多线程threading模块
目录 Thread对象 Lock对象 local对象 Thread对象: 多任务可以由多进程完成,也可以由一个进程内的多线程完成.进程是由至少1个线程组成的. threading模块在较低级的模块 _ ...
- python编程中的并发------多线程threading模块
任务例子:喝水.吃饭动作需要耗时1S 单任务:(耗时20s) for i in range(10): print('a正在喝水') time.sleep(1) print('a正在吃饭') time. ...
- [转]python 多线程threading简单分析
多线程和多进程是什么自行google补脑 对于python 多线程的理解,我花了很长时间,搜索的大部份文章都不够通俗易懂.所以,这里力图用简单的例子,让你对多线程有个初步的认识. 单线程 在好些年前的 ...
- 多线程threading模块
python的多线程编程 简介 多线程编程技术可以实现代码并行性,优化处理能力,同时功能的更小划分可以使代码的可重用性更好.Python中threading和Queue模块可以用来实现多线程编程. 详 ...
- Python多线程 - threading
目录 1. GIL 2. API 3. 创建子线程 4. 线程同步 4.1. 有了GIL,是否还需要同步? 4.1.1. 死锁 4.1.2. 竞争条件 4.1.3. GIL去哪儿了 4.2. Lock ...
- 学会使用Python的threading模块、掌握并发编程基础
threading模块 Python中提供了threading模块来实现线程并发编程,官方文档如下: 官方文档 添加子线程 实例化Thread类 使用该方式新增子线程任务是比较常见的,也是推荐使用的. ...
随机推荐
- 团队项目:二次开发--v.2.1--软件工程
原先代码,对于基本对象的Get,Set方法构造函数等方法与实现基本功能的方法统一放到了一起,容易造成代码不清晰,别人比较难阅读的情况.而且其中代码冗余比较多. 改进代码,进行了层次的分析,将基本对象与 ...
- c++之boost share_ptr
转载:https://www.cnblogs.com/welkinwalker/archive/2011/10/20/2218804.html
- form 表单添加 enctype ="multipart/form-data" 属性后后台接收中文乱码
解决办法: new String( request.getParameter("title").getBytes("ISO-8859-1"),"utf ...
- linux(rhel) rescue修复详解
修复linux,先准备好一张安装光盘,光驱安装好后开机,选择从光驱启动.等待安装盘显示操作界面时选择"rescue"选项,如果有光标提示的话,也可以输入:linux rescue进 ...
- 2018.09.26 bzoj1015: [JSOI2008]星球大战starwar(并查集)
传送门 并查集经典题目. 传统题都是把删边变成倒着加边,这道题是需要倒着加点. 处理方法是将每个点与其他点的边用一个vector存起来,加点时用并查集统计答案就行了. 代码: #include< ...
- C++之类和对象的特性
简介:C++并不是一个纯粹的面向对象的语言,而是一种基于过程和面向对象的混合型的语言. 凡是以类对象为基本构成单位的程序称为基于对象的程序,再加上抽象.封装.继承和多态就成为面向对象程序. 1.掌握类 ...
- C#-VS字符串、日期、时间和时间段
小知识 哈希表,内存中的对象,用速度很快的哈希表当字典表,记录主键和内容. @,遇到转义字符,不转义,直接输出,即就是.转义字符是反斜杠/ 全部的内置类型都用类和结构描述.值类型用结构,引用类型用类. ...
- MySQL性能调优与架构设计——第13章 可扩展性设计之 MySQL Replication
第13章 可扩展性设计之 MySQL Replication 前言: MySQL Replication 是 MySQL 非常有特色的一个功能,他能够将一个 MySQL Server 的 Instan ...
- PAT甲 1002. A+B for Polynomials (25) 2016-09-09 22:50 64人阅读 评论(0) 收藏
1002. A+B for Polynomials (25) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue T ...
- HDU1518 Square(DFS) 2016-07-24 15:08 49人阅读 评论(0) 收藏
Square Problem Description Given a set of sticks of various lengths, is it possible to join them end ...