当前位置:   article > 正文

python之路(13)线程

python的dil锁会导致只有一个正在运行的线程吗

前言

  对于python来说,因为有DIL锁的存在,在同一个进程中,一个cpu中同一时刻只能运行一个线程,无法并行,只能并发,但是python可以创建多个进程,每个进程可以分别占用一个cpu来运行线程,实现并行,但是创建多个进程很占用内存。

  并发:可以运行多个程序,不是同时进行进行

  并行:可以同时运行多个程序

  同步和异步:同步是一个任务遇到io等阻塞,一直等待用户完成操作,再执行下面的程序;异步如果遇到io等阻塞,先执行下面的程序,一旦等到用户完成操作,在回来执行之前的程序。

目录


 

线程创建和常用方法

 方法一:

import time

def Hi(name):
    print('你好:%s'%name)
    time.sleep(2) #睡两秒

if __name__ == '__main__':
    #创建了两个子线程
    # target是目标函数,args是函数的参数(以元组的形式传入)
    t1=threading.Thread(target=Hi,args=("chen",)) 
    t2=threading.Thread(target=Hi,args=('liu',))

    t1.start()
    t2.start()

 方法二:通过继承

import threading
import time

#通过类继承
class MyThread(threading.Thread):
     def __init__(self,name):
         threading.Thread.__init__(self)
         self.name = name

     def run(self): #开启线程后,默认执行run方法
         print("你好:%s\n"%self.name)
         time.sleep(3)

if __name__=='__main__':
    t1 = MyThread('chen')
    t2 = MyThread('liu')
    t1.start()
    t2.start()
    print('endind....')

 join():一旦子线调用了这个方法,主线程需要等子线程运行完了再运行主线程,不让主线程和子线程是同时运行的。

setDaemon(True):一旦子线程调用这个方法,就将子线程设置为守护线程(随着主线程的结束而结束)。 注:要在start()之前调用

 

 同步锁

  当不同线程同时使用一个全局变量的时候,就会出现数据混乱,同步锁的作用是,给线程的一段代码使用同步锁,在这段代码执行时,同一时刻只有一个线程在运行,也就是说加了同步锁的这段代码是串行的

  1. import threading
  2. import time
  3. def sub():
  4. global num
  5. lock.acquire() #添加同步锁
  6. temp = num
  7. time.sleep(0.001)
  8. num = temp-1
  9. lock.release() #释放同步锁
  10. num = 100
  11. l = []
  12. lock = threading.Lock() #创建同步锁
  13. for i in range(100):
  14. t = threading.Thread(target=sub)
  15. t.start()
  16. l.append(t)
  17. for t in l:
  18. t.join()
  19. print(num) 

 

递归锁

  在同步锁中,会产生一个问题,如果在两个线程中,它们互相需要对方的资源,但是双方又不能先把资源给对方,这样就会一直卡住,这样就引入递归锁。

  1. import threading
  2. import time
  3. class MyThread(threading.Thread):
  4. def actionA(self):
  5. A.acquire() #请求A的同步锁
  6. print("%s gotA %s\n"%(self.name,time.ctime()))
  7. time.sleep(2)
  8. B.acquire() #请求B的同步锁
  9. print("%s gotB %s\n"%(self.name,time.ctime()))
  10. time.sleep(1)
  11. B.release() #释放A的同步锁
  12. A.release() #释放B的同步锁
  13. def actionB(self):
  14. B.acquire()#请求B的同步锁
  15. print("%s gotA %s\n"%(self.name,time.ctime()))
  16. time.sleep(2)
  17. A.acquire() #请求A的同步锁
  18. print("%s gotB %s\n"%(self.name,time.ctime()))
  19. time.sleep(1)
  20. A.release() #释放A的同步锁
  21. B.release() #释放B的同步锁
  22. def run(self):
  23. self.actionA()
  24. time.sleep(0.5)
  25. self.actionB()
  26. if __name__ == '__main__':
  27. A=threading.Lock()
  28. B=threading.Lock()
  29. L=[]
  30. for i in range(5):
  31. t=MyThread()
  32. t.start()
  33. L.append(t)
  34. for i in L:
  35. i.join()
  36. print("ending....")
  37. #######################################################
  38. Thread-1 gotA Sat May 4 12:05:52 2019
  39. Thread-1 gotB Sat May 4 12:05:54 2019
  40. Thread-1 gotA Sat May 4 12:05:55 2019
  41. Thread-2 gotA Sat May 4 12:05:55 2019
  42. 卡住......

  线程1首先完成actionA()方法,然后别的线程开始执行,也就是说,这个时候,线程2的actionA()方法和线程1的actionB()方法同时执行,然后线程1中的actionA()的方法拿到A的同步锁,此时线程2中的actionB()拿到B的同步锁,之后线程1请求B的同步锁,但是B锁已经被线程1给拿走了,同样的线程1请求A的同步锁,但是A锁已经被线程2给拿走了,此时两个线程都等对方先释放锁,就卡住 了。

因此使用递归锁

  1. import threading
  2. import time
  3. class MyThread(threading.Thread):
  4. def actionA(self):
  5. r_lcok.acquire() #count=1
  6. print(self.name,"gotA",time.ctime())
  7. time.sleep(2)
  8. r_lcok.acquire() #count=2
  9. print(self.name, "gotB", time.ctime())
  10. time.sleep(1)
  11. r_lcok.release() #count=1
  12. r_lcok.release() #count=0
  13. def actionB(self):
  14. r_lcok.acquire()
  15. print(self.name, "gotB", time.ctime())
  16. time.sleep(2)
  17. r_lcok.acquire()
  18. print(self.name, "gotA", time.ctime())
  19. time.sleep(1)
  20. r_lcok.release()
  21. r_lcok.release()
  22. def run(self):
  23. self.actionA()
  24. self.actionB()
  25. if __name__ == '__main__':
  26. # A=threading.Lock()
  27. # B=threading.Lock()
  28. r_lcok=threading.RLock() #使用递归锁
  29. L=[]
  30. for i in range(5):
  31. t=MyThread()
  32. t.start()
  33. L.append(t)
  34. for i in L:
  35. i.join()
  36. print("ending....")  

递归锁里内部维护这一个计数器count,初始值为0,当请求锁的时候就加1,释放锁的时候就减1,只要计数器大于零,就没有别的线程可以拿到这把锁 

 

 同步对象(event)

  相当于一个线程标记(flag)

  1. #创建event对象
  2. event = threading.Event()
  3. event.wait() #相当于一个阻塞状态,直到别的线程event.set()
  4. event.set() #先当与告诉别的已经wait()的线程不用再阻塞了
  5. event.clear() #清除event,用来重新wait()  

 

信号量

  设置同一时刻线程的执行数目

  1. import threading,time
  2. class myThread(threading.Thread):
  3. def run(self):
  4. if semaphore.acquire(): #设置信号量
  5. print(self.name)
  6. time.sleep(3)
  7. semaphore.release() #释放信号量
  8. if __name__=="__main__":
  9. semaphore=threading.Semaphore(5) #设置5把锁,只有5个线程可以进入,同一时刻只能执行5个线程
  10. thrs=[]
  11. for i in range(100): #这里开启了100个子线程,如何不设置信号量,那100个子线程将同时执行
  12. thrs.append(myThread())
  13. for t in thrs:
  14. t.start()  

 

 线程队列

  1. import queue # 线程 队列
  2. q=queue.Queue() # 创建一个队列,可以设置队列里的最大存放个数
  3. q.put(12)
  4. q.put("hello")
  5. q.put({"name":"yuan"}) #在put时,如果队列的值是满的,就会卡住,直到别的线程将值取走,队列里有空位了,才将值放进队列里
  6. while 1:
  7. data=q.get() #如果这里的get()是里面没有值的话,就会一直卡住,直到比的线程往队列里面put()值
  8. print(data)
  9. print("----------")

  put('chen',False)  可以设置如果队列里是满的,就报错,同样 get(block=False) 也是一样

 q=queue.LifoQueue() 创建后进先出的队列,相当于栈

 q=queue.PriorityQueue() 创建按照优先级决定进出的队列  

  1. import queue # 线程 队列
  2. q=queue.PriorityQueue() # 创建一个优先级队列
  3. q.put([3,12]) #列表带着优先级,数字越小,优先级越高
  4. q.put([2,"hello"])
  5. q.put([4,{"name":"yuan"}])
  6. while 1:
  7. data=q.get()
  8. print(data[1])
  9. print("----------")
  10. ############################
  11. hello
  12. ----------
  13. 12
  14. ----------
  15. {'name': 'yuan'}
  16. ----------

 q.qsize() 返回队列的大小

 q.empty() 如果队列为空,返回true,如果队列不会空,返回false

 q.get_nowait() 相当于 q.get(block=False) ,不等待,直接报错

 q.task_done()  会给 q.join()发信号

 q.join() 等待接收来自 q.task_done() 的信号,不然一直卡住 

 

 生产者和消费者模型

  在多线程开发过程中,如果生产数据的线程处理的速度很快,但是消费数据的线程处理的很慢,那么就必须等到消费数据的线程处理完,才可以进行生产数据,反之,如果生产数据的处理速度小于消费数据的处理速度,那么消费线程就必须等待生产线程。

  因此生产者和消费者模型是在彼此之间不做任何通信,通过阻塞队列来进行通信,生产线程生产完数据后,直接扔给阻塞队列,而消费者直接从阻塞队列里区,阻塞队列就相当于一个缓冲区。(解耦问题)

import time,random
import queue,threading

q = queue.Queue()

def Producer(name):
  count = 0
  while count <10:
    print("making........")
    time.sleep(5)
    q.put(count)
    print('Producer %s has produced %s baozi..' %(name, count))
    count +=1
    #q.task_done()
    q.join()
    print("ok......")

def Consumer(name):
  count = 0
  while count <10:
        time.sleep(random.randrange(4))
    # if not q.empty():
    #     print("waiting.....")
        #q.join()
        data = q.get()
        print("eating....")
        time.sleep(4)

        q.task_done()
        #print(data)
        print('\033[32;1mConsumer %s has eat %s baozi...\033[0m' %(name, data))
    # else:
    #     print("-----no baozi anymore----")
        count +=1

p1 = threading.Thread(target=Producer, args=('A君',))
c1 = threading.Thread(target=Consumer, args=('B君',))
c2 = threading.Thread(target=Consumer, args=('C君',))
c3 = threading.Thread(target=Consumer, args=('D君',))

p1.start()
c1.start()
c2.start()
c3.start()
View Code

 

转载于:https://www.cnblogs.com/shuzhixia/p/10806360.html

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号