多进程(补充),多线程,锁教程
<strong>多进程补充</strong><br></br>joinable Queue<br></br><br></br>q=JoinableQueue<br></br>q.put(1)<br></br>q.put(2)<br></br>print(q.get())<br></br>q.task_done() <strong>告诉容器已经处理完成了一个数据 有几个数据就要调用几次</strong><br></br>q.task_done()<br></br><br></br>q.join() <strong>也是一个阻塞函数 一直到队列中的数据被处理完毕(task_done的调用次数等于队列中的数据数量)</strong><br></br>print('处理完成')<br></br><br></br>
# 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("\033[46m生产者 生产了hot_dog%s\033[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()
# #王思聪就不需要在吃了
生产者消费者模型
<br></br><br></br><br></br>进程池<br></br>1.多线程理论(重点)<br></br>2.多线程使用方法(重点)<br></br> 两种创建方式<br></br> 常用属性<br></br>锁<br></br>互斥锁<br></br>死锁<br></br><br></br><br></br><strong>操作系统就像一个工厂</strong><br></br><br></br><strong>线程值的是一条流水线 整个执行过程的总称 也是一个抽象概念</strong><br></br><strong>线程是CPU的最小执行单位 是具体负责执行代码的</strong><br></br><br></br>进程是一个资源单位,其中包括了改程序运行所需的所有资源<br></br>线程相当于车间里的一条流水线<br></br>线程的特点:<br></br> 一个进程中至少包括一个线程 是由操作系统自动创建的 称之为主线程<br></br> 一个进程中可以有任意数量的线程<br></br> 创建线程的开销对比进程而言 要小的多<br></br> <strong>同一个进程中的线程间数据是共享的(最主要的特点)</strong><br></br><br></br>如何使用:使用的方式与进程一致<br></br>不同的是:创建线程的代码可以写在任何位置<br></br><br></br>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()
两种线程创建方式
<br></br><br></br><br></br><strong>开启线程速度 比开启进程快很多</strong><br></br><br></br><strong>主线程任务执行完毕后 进程不会立即结束 会等待所有子线程执行完毕</strong><br></br><strong>在同一进程中 所有线程都是平等的 没有子父一说</strong><br></br>from threading import Thread<br></br>import time<br></br><br></br>def task():<br></br> print("子线程 running.....")<br></br> time.sleep(3)<br></br> print("子线程 over......")<br></br><br></br>t = Thread(target=task)<br></br>t.start()<br></br>print("main over")<br></br><br></br><strong>线程与进程的区别之一 数据是共享的</strong><br></br><strong>区别二 创建进程与创建线程的开销 大约是一百多倍</strong><br></br><br></br>
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)
<br></br><br></br><strong>线程安全也是通过锁来保证 所得用法与进程中一模一样<br></br></strong>
# 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.有多把锁,一个线程抢一把锁,要完成任务必须同时抢到所有的锁 将导致死锁问题
![多进程(补充),多线程,锁教程](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)![多进程(补充),多线程,锁教程](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
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()