python 多线程
import threading import time def run(n): print("task",n) time.sleep(2) t1=threading.Thread(target=run,args=("t1",))#一个参数也要用逗号 t2=threading.Thread(target=run,args=("t2",)) t1.start() t2.start() #最简单的多线程
过程的名字可以随便,但是在下面的类里面就必须用RUN
import threading import time class MyThread(threading.Thread): def __init__(self,n): super(MyThread,self).__init__() self.n=n def run(self):#如果是一个DEF 那么就可以是任意的名字,但是在类里面他就必须叫run print("running task:"%self.n) t1=MyThread('t1') t2=MyThread('t2') t1.start() t2.start()
这就是多线程的两种写法。
算程序运行的时间
import threading import time starttime=time.time() def run(n): print("task",n) time.sleep(2) for i in range(50): t=threading.Thread(target=run,args=("t%s"%i,))#一个参数也要用逗号 t.start() curenttime=time.time() cha=curenttime-starttime print("cost %s秒"%cha) #这样是测不出来运行时间的因为是并行的主线程和子线程没关系 都在运行
应该用
import threading import time starttime=time.time() def run(n): print("task",n) time.sleep(2) t_object=[] for i in range(50): t=threading.Thread(target=run,args=("t%s"%i,))#一个参数也要用逗号 t.start() t_object.append(t) for ii in t_object:#等待所有的线程都进行完 ii.join() print(ii,"结束") curenttime=time.time() cha=curenttime-starttime print("cost %s秒"%cha)
守护线程的意义
import threading import time starttime=time.time() def run(n): print("task",n) time.sleep(2) t_object=[] for i in range(50): t=threading.Thread(target=run,args=("t%s"%i,))#一个参数也要用逗号 t.setDaemon(True)#设置线程为守护线程,就是跟主线程关系不大主线程不会等他执行的结果,主线程执行完就完了,没守护线程什么事儿了。 t.start() t_object.append(t) for ii in t_object:#等待所有的线程都进行完 ii.join() print(ii,"结束") curenttime=time.time() cha=curenttime-starttime print("cost %s秒"%cha)
正常来讲,这个num结果应该是0, 但在python 2.7上多运行几次,会发现,最后打印出来的num结果不总是0,为什么每次运行的结果不一样呢? 哈,很简单,假设你有A,B两个线程,此时都 要对num 进行减1操作, 由于2个线程是并发同时运行的,所以2个线程很有可能同时拿走了num=100这个初始变量交给cpu去运算,当A线程去处完的结果是99,但此时B线程运算完的结果也是99,两个线程同时CPU运算的结果再赋值给num变量后,结果就都是99。那怎么办呢? 很简单,每个线程在要修改公共数据时,为了避免自己在还没改完的时候别人也来修改此数据,可以给这个数据加一把锁, 这样其它线程想修改此数据时就必须等待你修改完毕并把锁释放掉后才能再访问此数据。
*注:不要在3.x上运行,不知为什么,3.x上的结果总是正确的,可能是自动加了锁
import time import threading def addNum(): global num #在每个线程中都获取这个全局变量 print('--get num:',num ) time.sleep(1) lock.acquire() #修改数据前加锁 num -=1 #对此公共变量进行-1操作 lock.release() #修改后释放 num = 100 #设定一个共享变量 thread_list = [] lock = 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 )
RLock(递归锁)
说白了就是在一个大锁中还要再包含子锁
import threading,time def run1(): print("grab the first part data") lock.acquire() global num num +=1 lock.release() return num def run2(): print("grab the second part data") lock.acquire() global num2 num2+=1 lock.release() return num2 def run3(): lock.acquire() res = run1() print('--------between run1 and run2-----') res2 = run2() lock.release() print(res,res2) if __name__ == '__main__': num,num2 = 0,0 lock = threading.RLock() for i in range(10): t = threading.Thread(target=run3) t.start() while threading.active_count() != 1: print(threading.active_count()) else: print('----all threads done---') print(num,num2)
Semaphore(信号量)
互斥锁 同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据 ,比如厕所有3个坑,那最多只允许3个人上厕所,后面的人只能等里面有人出来了才能再进去。
import threading,time def run(n): semaphore.acquire() time.sleep(1) print("run the thread: %s\n" %n) semaphore.release() if __name__ == '__main__': num= 0 semaphore = threading.BoundedSemaphore(5) #最多允许5个线程同时运行 for i in range(20): t = threading.Thread(target=run,args=(i,)) t.start() while threading.active_count() != 1: pass #print threading.active_count() else: print('----all threads done---') print(num)
通过Event来实现两个或多个线程间的交互,下面是一个红绿灯的例子,即起动一个线程做交通指挥灯,生成几个线程做车辆,车辆行驶按红灯停,绿灯行的规则。
import threading,time import random def light(): if not event.isSet(): event.set() #wait就不阻塞 #绿灯状态 count = 0 while True: if count < 10: print('\033[42;1m--green light on---\033[0m') elif count <13: print('\033[43;1m--yellow light on---\033[0m') elif count <20: if event.isSet(): event.clear() print('\033[41;1m--red light on---\033[0m') else: count = 0 event.set() #打开绿灯 time.sleep(1) count +=1 def car(n): while 1: time.sleep(random.randrange(10)) if event.isSet(): #绿灯 print("car [%s] is running.." % n) else: print("car [%s] is waiting for the red light.." %n) if __name__ == '__main__': event = threading.Event() Light = threading.Thread(target=light) Light.start() for i in range(3): t = threading.Thread(target=car,args=(i,)) t.start()
queue
这个队列就像一个列表,但是他是共用的,而且谁都 可以从里面拿数据,但是如果有人拿走了,那里面的数据就没有了
# -*- encoding:utf-8 -*- import queue a=queue.PriorityQueue() a.put((5,8)) a.put((1,9)) a.put((2,3)) print(a.get()[1]) print(a.get()[1]) print(a.get()[1]) # print(a.get()) b=queue.Queue()#先入先出 b.put(1);b.put(2);b.put(3) print(b.get());print(b.get());print(b.get()) c=queue.Queue(3)#最大入入多少数据 c.put(1);c.put(2);c.put(3) print(c.get());print(c.get())#放进去不会报错会卡住,其他都 是一样 都有这个MAXSIZE print(a.qsize(),"a的大小");print("c的大小",c.qsize())
生产者消费者模型
在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题。该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度。
为什么要使用生产者和消费者模式
在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程。在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这个问题于是引入了生产者和消费者模式。
什么是生产者消费者模式
生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。
import queue import time import threading q=queue.Queue(10) def produce(name): count=1 while True: q.put("骨头%s"%count) print(count,'生产了') time.sleep(0.5) count+=1 def comstem(name): while q.qsize()>0: print("%s 取到了%s并且吃了他"%(name,q.get())) print("还剩下%s"%q.qsize()) time.sleep(1) t1=threading.Thread(target=produce,args=("xiaoxu",)) t2=threading.Thread(target=comstem,args=('liyao',)) t1.start() t2.start()
多线程和多进程 的使用方法
IO 不占CPU
计算占用CPU
多进程
在一个进程 里面再去行一个线程
import time,threading import multiprocessing def thread_run(): print(threading.get_ident()) def process_run(name): time.sleep(2) print("hello",name) t=threading.Thread(target=thread_run) t.start() if __name__ == '__main__': for i in range(10): p=multiprocessing.Process(target=process_run,args=('bob %s'%i,)) p.start()
多进程 里面各进程间需要数据,需要一个进程QUENEN
import time from multiprocessing import Queue,Process def f(qq): qq.put('我是QUENE里面的值') if __name__=='__main__':#y主进程 qq=Queue()#在主进程里面有一个QUENES p=Process(target=f,args=(qq,))#生成了一个子进程,在子进程里面在QUENE里面放了一个值 p.start() print(qq.get())#在主进程调用QUENE里面看看子进程里面放的值