一、生产者消费者模型1
二、生产者消费者模型2
三、守护线程
四、常用方法
五、启动线程的另一种方式
六、锁
七、锁死
八、死锁
九、单个锁能不能死锁
十、信号旗
一、生产者消费者模型1
import time,random from multiprocessing import Process,Queue # 制作热狗 def make_hotdog(queue,name): for i in range(3): time.sleep(random.randint(1,2)) print("%s 制作了一个热狗 %s" % (name,i)) # 生产得到的数据 data = "%s生产的热狗%s" % (name,i) # 存到队列中 queue.put(data) # 装入一个特别的数据 告诉消费方 没有了 #queue.put(None) # 吃热狗 def eat_hotdog(queue,name): while True: data = queue.get() if not data:break time.sleep(random.randint(1, 2)) print("%s 吃了%s" % (name,data)) if __name__ == '__main__': #创建队列 q = Queue() p1 = Process(target=make_hotdog,args=(q,"邵钻钻的热狗店")) p2 = Process(target=make_hotdog, args=(q, "egon的热狗店")) p3 = Process(target=make_hotdog, args=(q, "老王的热狗店")) c1 = Process(target=eat_hotdog, args=(q,"思聪")) c2 = Process(target=eat_hotdog, args=(q, "李哲")) p1.start() p2.start() p3.start() c1.start() c2.start() # 让主进程等三家店全都做完后.... p1.join() p2.join() p3.join() # 添加结束标志 注意这种方法有几个消费者就加几个None 不太合适 不清楚将来有多少消费者 q.put(None) q.put(None) # 现在 需要知道什么时候做完热狗了 生产者不知道 消费者也不知道 # 只有队列知道 print("主进程over") # 生产方不生产了 然而消费方不知道 所以已知等待 get函数阻塞 # 三家店都放了一个空表示没热狗了 但是消费者只有两个 他们只要看见None 就认为没有了 # 于是进程也就结束了 造成一些数据没有被处理 # 等待做有店都做完热狗在放None
二、生产者消费者模型2
import time,random from multiprocessing import Process,JoinableQueue # 制作热狗 def make_hotdog(queue,name): for i in range(3): time.sleep(random.randint(1,2)) print("%s 制作了一个热狗 %s" % (name,i)) # 生产得到的数据 data = "%s生产的热狗%s" % (name,i) # 存到队列中 queue.put(data) # 装入一个特别的数据 告诉消费方 没有了 #queue.put(None) # 吃热狗 def eat_hotdog(queue,name): while True: data = queue.get() time.sleep(random.randint(1, 2)) print("%s 吃了%s" % (name,data)) # 该函数就是用来记录一共给消费方多少数据了 就是get次数 queue.task_done() if __name__ == '__main__': #创建队列 q = JoinableQueue() p1 = Process(target=make_hotdog,args=(q,"邵钻钻的热狗店")) p2 = Process(target=make_hotdog, args=(q, "egon的热狗店")) p3 = Process(target=make_hotdog, args=(q, "老王的热狗店")) c1 = Process(target=eat_hotdog, args=(q,"思聪")) c2 = Process(target=eat_hotdog, args=(q, "李哲")) p1.start() p2.start() p3.start() # 将消费者作为主进程的守护进程 c1.daemon = True c2.daemon = True c1.start() c2.start() # 让主进程等三家店全都做完后.... p1.join() p2.join() p3.join() # 如何知道生产方生产完了 并且 消费方也吃完了 # 方法一:等待做有店都做完热狗在放None # # 添加结束标志 注意这种方法有几个消费者就加几个None 不太合适 不清楚将来有多少消费者 # q.put(None) # q.put(None) # 主进程等到队列结束时再继续 那队列什么时候算结束? 生产者已经生产完了 并且消费者把数据全取完了 q.join() # 已经明确生产放一共有多少数据 # 现在 需要知道什么时候做完热狗了 生产者不知道 消费者也不知道 # 只有队列知道 print("主进程over") # 生产方不生产了 然而消费方不知道 所以一直等待 get函数阻塞 # 三家店都放了一个空表示没热狗了 但是消费者只有两个 他们只要看见None 就认为没有了 # 于是进程也就结束了 造成一些数据没有被处理
三、守护线程
from threading import Thread
import time
def task():
time.sleep(5)
print("子线程...")
t = Thread(target=task)
t.daemon = True # 守护线程 执行顺序与进程中一样
t.start()
print("over")
四、线程
from threading import Thread # a = 100 # # def task(): # global a # a = 1 # print("这是给子线程执行的任务!") # # # 创建一个子线程 # t = Thread(target=task) # # 启动这个子线程 # t.start() # print("主") # print(a) # 在多进程中 开启子进程需要消耗大量的资源 所以主进程会先比子进程执行 # 子线程的开启速度比进程快的多 # 在多线程中 子线程可以直接访问主线程的内容 # 多个线程之间时平等的 所以不存在父子关系 # 在今后的开发中 每当出现i/o阻塞 比较耗时的操作 import time,os def task(): time.sleep(2) print("子线程 run.....") print(os.getpid()) t = Thread(target=task) t.start() # 主线程等到子线程结束 t.join() print("over") print(os.getpid())
五、常用方法
from threading import Thread,current_thread,active_count,enumerate import time def task(): print("子线程...") time.sleep(1) # 获取当前线程对象 非常常用 print(current_thread()) t = Thread(target=task,name="矮根线程!") # t.daemon = True # 守护线程 执行顺序与进程中一样 print(t.name) print(t) t.start() # 获取当前活跃线程的数量 print(active_count()) # 返回活跃的线程对象枚举 print(enumerate()) print("over")
六、启动线程的另一种方式
from threading import Thread,current_thread class MyThread(Thread): def run(self): print("run 函数执行!") print(current_thread()) mt = MyThread() mt.start() print(current_thread())
七、锁
from threading import Thread,Lock # 创建一个互斥锁 mutex = Lock() def task1(): # 锁定 mutex.acquire() for i in range(100): print("===================") # 打开 mutex.release() def task2(): mutex.acquire() for i in range(100): print("!!!!!!!!!!!!!!!!!!") mutex.release() def task3(): mutex.acquire() for i in range(100): print("********************") mutex.release() t1 = Thread(target=task1) t2 = Thread(target=task2) t3 = Thread(target=task3) t1.start() t2.start() t3.start()
八、锁死
from threading import Thread,Lock
import time,random
mutex1 = Lock()
mutex2 = Lock()
def fun1():
mutex1.acquire()
print("抢到了锁1")
time.sleep(1)
mutex2.acquire()
print("抢到了锁2")
mutex2.release()
print("释放了锁2")
mutex1.release()
print("释放了锁1")
def fun2():
mutex2.acquire()
print("抢到了锁2")
time.sleep(1)
mutex1.acquire()
print("抢到了锁1")
mutex1.release()
print("释放了锁2")
mutex2.release()
print("释放了锁1")
# def fun3():
# fun1()
# fun2(
t1 = Thread(target=fun1)
t1.start()
t2 = Thread(target=fun2)
t2.start()
九、死锁
from threading import Thread,Lock,current_thread,RLock import time # 叉子 locka = RLock() # 盘子 lockb = RLock() def task1(): print(current_thread()) locka.acquire() print("抢到叉子 需要盘子") time.sleep(0.1) lockb.acquire() print("吃饭") lockb.release() locka.release() def task2(): print(current_thread()) lockb.acquire() print("抢到盘子 需要叉子") time.sleep(0.1) locka.acquire() print("吃饭") locka.release() lockb.release() t1 = Thread(target=task1) t1.start() t2 = Thread(target=task2) t2.start() # 死锁发生的条件 有多个线程 多个锁 如果只有一个锁 无论是LOCK RLOK 卡不死(前提是逻辑上没有错误) # RLock 就算你的代码逻辑不对 同一个线程多次对一个锁执行acquire 也不会卡死
十、单个锁能不能死锁
from threading import Thread,Lock,RLock,current_thread l = Lock() # 互斥锁 # l.acquire() # print("zxxzxxxzxzx") # l.acquire() # print("aaaaaaaaa") # RLock 递归锁 重入锁 可以多次执行acquire # lock = RLock() # # lock.acquire() # print("aaaaaaaaaaa") # lock.acquire() # print("bbbbbbbbbbb") import time lock = RLock() # 对于同一个线程而言 可以多次acquire 其他线程会被阻塞 def task(): lock.acquire() for i in range(5): time.sleep(1) print(current_thread()) lock.release() Thread(target=task).start() Thread(target=task).start() #
十一、信号旗
from threading import Thread,Semaphore,current_thread,active_count import time # 用于控制 同时执行被锁定代码的线程数量 也就是线程的并发数量 # 也是一种锁 sm = Semaphore(1) def task(): sm.acquire() for i in range(10): print(current_thread()) time.sleep(0.5) sm.release() def task2(): for i in range(10): print(current_thread()) time.sleep(0.5) for i in range(5): Thread(target=task).start() Thread(target=task2).start() print(active_count())
线程和进程的区别
进程是一个资源单位
一个进程可以包含多个线程
多个线程之间的数据可以共享
线程开销比进程小
在多个线程中CPU切换速度会比非常快,但资源消耗没有进程高