1.并发并行与同步异步的概念
- 并发:指系统具有处理多个任务(动作)的能力
- 并行:指系统具有同时处理多个任务(动作)的能力
- 同步:进程在IO操作时进行等待
- 异步:进程在IO操作时不等待,处理其他事情,IO操作完成再回来继续执行。
2.GIL概念
GIL是python解释器在程序的每个进程上加了一把锁,在这个进程中, 同时只允许一个线程运行。
在同一个进程内,不同的线程会竞争cpu的使用权。
由于GIL的存在,理论上串行的效果比较好,但是遇到IO操作,计算密集型操作的时候,多线程处理速度较快
2.1 解决方法
- 开启不同的进程
- 多进程+协程
pass:作为一个程序员,除了python之外,肯定还要掌握其他语言,只学习python肯定是不够的。
3.同步锁
多个线程在对同一个数据进行处理时,可能导致重复对数据进行处理,不能得到及时反馈,所以给线程加一把锁,当某个线程在执行的时候,其他线程不能使用,等这个线程执行好数据之后再进行竞争。
import threading,time num=100 def test(): global num lock.acquire()#获取这把锁 temp=num time.sleep(0.01) num=temp num -=1 lock.release()#释放这把锁,在这个过程中 l=[] lock=threading.Lock() for i in range(100): t=threading.Thread(target=test) t.start() l.append(t) for x in l: x.join()#时间可能改变的原因:第一次循环进行时,在num的结果还没有计算出来时,第二次循环就开始了,导致第二次num拿到的值和第二次一样 print(num)
当多个线程同时对一个全局变量进行处理时,在一个变量没有处理完是,比如说100-1,下一个线程已经开始运算,但是拿到的数据不是99,依旧是100,多个线程做了重复的无用工作,用同步锁将线程锁住,等这个线程执行完之后,其他的线程再执行,实质上是进行串行处理。
4.递归锁-死锁
当两个线程,加了两把锁的时候,a线程加上a锁,b线程加上b锁,当a再去需要b锁,b需要a锁的时候,两个线程互相掰手腕,就形成了死锁
import threading, time class Mythread(threading.Thread): def run(self): self.actionA()#运行a线程 # time.sleep(8.1 # ) self.actionB()#运行b线程 def actionA(self): A.acquire()#获得一把a锁 print(self.name, time.ctime())#打印时间 time.sleep(2)#休眠两秒,此时其他线程正在等待a运行完 B.acquire()#获得b锁 print(self.name, time.ctime()) time.sleep(2) B.release() A.release()#释放a和b锁,此时其他线程开始竞争,,线程a开始执行b动作 def actionB(self): B.acquire()#在a线程获得b锁的同事,其他线程B获得a锁 print(self.name, time.ctime()) time.sleep(2) A.acquire()#a想要获得a锁的时候,b已经获得a锁,互不相让 print(self.name, time.ctime()) A.release() B.release() if __name__ == '__main__': A = threading.Lock() B = threading.Lock() L = [] for i in range(5): t = Mythread() t.start() L.append(t) for i in L: i.join()
5.同步对象event
用于多线程之间进行沟通,只有是true的时候才继续运行
- event.wait==>false
- event.set==>true
- event.clear==>清空状态,false
import threading,time class Mythreading(threading.Thread): def __init__(self): super(Mythreading,self).__init__() def run(self): print('this is run') time.sleep(2) print('this is wait') event.wait() l=[] event=threading.Event() for i in range(4): l.append(Mythreading()) for s in l: s.start()#运行run方法 # s.join()#如果是单个线程的话,没有线程来给他解决wait的问题 print('准备开始激活') event.()#主线程激活的
6.信号量
最多只能同时执行多少个线程
相当于一个新的锁,锁住只能特定线程
import threading,time class Myclass(threading.Thread): def run(self): if sema.acquire(): print(self.name) time.sleep(3) sema.release() if __name__ == '__main__': sema=threading.Semaphore(5) l=[] for i in range(100): l.append(Myclass()) for s in l: s.start()
7.线程队列 queue
可以实现多个线程之间进行通讯
q=queue.Queue(4)#最多只能放入四个数据
q.put()====在队列中放入数据
q.get()===从队列中取出数据
q.put(5,false)===将5放入数据,如果数据满了直接报错
q.get(5,false)==同上
7.1 queue队列的进出模式
- 默认先进先出模式
- 先进后出q=queue.LifoQueue
- 优先级模式 q=queue.PriorityQueue
q=queue.PriorityQueue() q.put(1,'546')#546的有些级别为1
7.2 队列的方法
- q.size()==>队列的方法
- q.empty()==>返回队列是否为空
- q.ful()==>同上
- q.get_nowait()==q.get(5,false)
7.3 task_done,join
一个task_done对应一个join,join的时候程序是阻塞的,当得到一个done的时候继续运行。、
# import queue # # # # q=queue.Queue(5)#这个队列最多只能存储五个数据 # # # # q.put('123') # # q.put('alex') # # # q.put(['alex']) # # q=queue.PriorityQueue() # # q.put(1,'546')#546的有些级别为1 # # # # a=q.get() # # b=q.get() # # print(a) # # print(b) # import threading,time,queue # class Myclass(threading.Thread): # def __init__(self,que): # threading.Thread.__init__(self) # self.que=que # def run(self): # while 1: # time.sleep(1) # if self.queue.empty(): # break # item=self.queue.get() # print(item,'11') # return # # q=queue.Queue() # # l=[] # for i in range(2): # l.append(Myclass('que')) # # for x in range(10): # # q.put(x) # # for m in l: # m.start() # q.join() # import threading import queue from time import sleep que = queue.Queue() class Testthread(threading.Thread): def __init__(self, que):#继承线程父类 threading.Thread.__init__(self) self.queue = que def run(self):#自定义run while True: sleep(1) item = self.queue.get()#从队列中拿数据 print(item) # self.queue.task_done()#拿完之后done一下,这样别的线程就知道这个动作完成了 tasks = [Testthread(que) for x in range(2)]#连哥哥线程 for x in range(10): que.put(x)#在队列中放入是个数据,就是创建了一个队列,然后在队列中拿数据 for x in tasks: t = Testthread(que)#将这两个线程启动 # t.setDaemon(True) t.start() que.join()#之后阻塞 # print('这个是等待挂起') print('all done')#如果内有taskdone,join后的程序将无法得到执行