多进程补充
joinable Queue
q=JoinableQueue
q.put(1)
q.put(2)
print(q.get())
q.task_done() 告诉容器已经处理完成了一个数据 有几个数据就要调用几次
q.task_done()
q.join() 也是一个阻塞函数 一直到队列中的数据被处理完毕(task_done的调用次数等于队列中的数据数量)
print('处理完成')
# from multiprocessing import Process,Queue,JoinableQueue
# import time,random
#
# # 生产者
# def make_hot_dog(q):
# for i in range(1,6):
# time.sleep(random.randint(1,3))
# print(" 33[46m生产者 生产了hot_dog%s 33[0m" % i)
# q.put("hot_dog%s" % i)
# # 消费者
# def eat_hot_dog(q):
# while True:
# time.sleep(random.randint(1, 2))
# hot_dog = q.get()
# print("思聪吃了%s" % hot_dog)
# q.task_done()
#
#
# if __name__ == '__main__':
# # 共享数据的队列
# q = JoinableQueue()
#
# # 生产者
# p1 = Process(target=make_hot_dog,args=(q,))
# p2 = Process(target=make_hot_dog,args=(q,))
# p1.start()
# p2.start()
#
#
# # 消费者
# c1 = Process(target=eat_hot_dog,args=(q,))
# c1.daemon = True
# c1.start()
#
# # print("完成了吗???")
# #先要确定生产者已经不会再生产了
# p1.join()
# p2.join()
#
# print("生产已经结束了...")
# #再确定队列中的所有数据都被处理完成
# q.join()
# print("思聪已经全部吃完了....")
#
#
# # c1.terminate()
# #王思聪就不需要在吃了
生产者消费者模型
进程池
1.多线程理论(重点)
2.多线程使用方法(重点)
两种创建方式
常用属性
锁
互斥锁
死锁
操作系统就像一个工厂
线程值的是一条流水线 整个执行过程的总称 也是一个抽象概念
线程是CPU的最小执行单位 是具体负责执行代码的
进程是一个资源单位,其中包括了改程序运行所需的所有资源
线程相当于车间里的一条流水线
线程的特点:
一个进程中至少包括一个线程 是由操作系统自动创建的 称之为主线程
一个进程中可以有任意数量的线程
创建线程的开销对比进程而言 要小的多
同一个进程中的线程间数据是共享的(最主要的特点)
如何使用:使用的方式与进程一致
不同的是:创建线程的代码可以写在任何位置
from threading import Thread
# 第一种 开启线程的方式 直接实例化Thread类
# from threading import Thread
#
# def task():
# print('running....')
#
#
# if __name__ == '__main__':
# t=Thread(target=task)
# t.start()
# print('over')
#
# # 2.继承Thread类 覆盖run方法
# class MyThread(Thread):
# def run(self):
# print('running...')
# MyThread().start()
# #t=MyThread()
# #t.start()
两种线程创建方式
开启线程速度 比开启进程快很多
主线程任务执行完毕后 进程不会立即结束 会等待所有子线程执行完毕
在同一进程中 所有线程都是平等的 没有子父一说
from threading import Thread
import time
def task():
print("子线程 running.....")
time.sleep(3)
print("子线程 over......")
t = Thread(target=task)
t.start()
print("main over")
线程与进程的区别之一 数据是共享的
区别二 创建进程与创建线程的开销 大约是一百多倍
from multiprocessing import Process
import os
def task():
print(os.getpid())
pass
if __name__ == '__main__':
start = time.time()
ps = []
for i in range(100):
p = Thread(target=task)
# p = Process(target=task)
p.start()
ps.append(p)
for p in ps:
p.join()
print(time.time()-start)
线程安全也是通过锁来保证 所得用法与进程中一模一样
# import time
# from threading import Thread,Lock
#
# num = 10
# lock = Lock()
#
# def task():
# global num
# # lock.acquire()
# a = num
# time.sleep(0.1)
# num = a - 1
# # lock.release()
#
#
# ts = []
# for i in range(10):
# t = Thread(target=task)
# t.start()
# ts.append(t)
#
# for t in ts:
# t.join()
#
#
# print(num)
线程安全
开发高并发程序很有可能遇到安全问题
解决方案只有加锁 但是在使用锁时 很有可能出现死锁问题
出现死锁问题的两种情况:
1.对同一把锁调用了多次acquire 导致死锁问题(最low的死锁问题 应该避免这种问题)
2.有多把锁,一个线程抢一把锁,要完成任务必须同时抢到所有的锁 将导致死锁问题
from threading import Lock,Thread
import time
# lock = Lock()
# lock.acquire()
# lock.acquire()
# print("over")
# 一个盘子 和一双筷子
# lock1 = Lock()
# lock2 = Lock()
#
# def task1(name):
# lock1.acquire()
# print("%s 抢到了盘子" % name)
#
# time.sleep(1)
#
# lock2.acquire()
# print("%s 抢到了筷子" % name)
#
# print("%s 吃饭了....." % name)
#
# lock1.release()
# lock2.release()
#
#
# def task2(name):
# lock2.acquire()
# print("%s 抢到了筷子" % name)
#
# lock1.acquire()
# print("%s 抢到了盘子" % name)
#
# print("%s 吃饭了....." % name)
#
# lock1.release()
# lock2.release()
#
#
#
# t1 = Thread(target=task1,args=("渣渣辉",))
# t1.start()
#
# t2 = Thread(target=task2,args=("大导演",))
# t2.start()
死锁
如何避免:
1.能不加锁就不加
2.如果一定要加 要保证锁只有一把
RLock只能防止同一个问题 统一线程多次执行acquire
from threading import RLock
# lock = RLock()
# lock.acquire()
# lock.acquire()
# lock.acquire()
# lock.acquire()
#
# print("over")
# lock = RLock()
#
# def task1():
# lock.acquire()
# def task2():
# lock.acquire()
#
# Thread(target=task1).start()
# Thread(target=task2).start()
信号量 Semaphore(num) 可以控制同一时间有多少线程可以并发的访问
不是用来处理线程安全问题
from threading import Semaphore
s_lock = Semaphore(3)
def task():
s_lock.acquire()
time.sleep(1)
print("run.....")
s_lock.release()
for i in range(20):
t = Thread(target=task)
t.start()
threading.current_thread() # 获取当前线程
threading.active_count() 正在运行中的线程数量
threading.enumerate() 返回所有正在运行的线程对象
守护线程会在主线程结束后立即结束 即使任务没有完成
主线程会等待所有子线程全部完成后才会结束
守护线程会在所有非守护线程结束后 结束*****
主线 守护线程
主线程要等待所有子线程结束
from threading import Semaphore
s_lock = Semaphore(3)
def task():
s_lock.acquire()
time.sleep(1)
print("run.....")
s_lock.release()
for i in range(20):
t = Thread(target=task)
t.start()