2019-04-18-day035-守护线程与池
2024-10-08 20:36:10
内容回顾
- 互斥锁
- 在同一个进程中连续锁两次以上会死锁
- 进程的数据共享
- 进程之间可以共享数据
- 提供共享数据的类是Manager
- 但是他提供的list\dict这些数据类型是数据不安全的
- 针对 += -= *= /=
- 需要加锁来保证安全
- 用到了进程之间的通信
- 队列 queue
- 管道
- manager
- lock
- Process
- 线程
- 概念
- 进程和线程的区别
- 进程 开销大 数据隔离
- 是计算机中最小的资源分配单位
- 线程 轻量级 共享数据
- 是计算机中能被CPU调度的最小单位
- 进程 开销大 数据隔离
- 正常的线程是什么样子
- 能同时被多个CPU执行
- Cpython解释器下的线程
- GIL锁
- 全局解释器锁
- 是Cpython解释器中的
- 会导致同一时刻只能有一个线程访问CPU
- GIL锁
- 进程和线程的区别
- 代码threading模块
- Thread类
- 开启线程
- 传参数
- join
- 没有terminate
- active_count int 当前程序中正在执行的线程个数
- current_thread 线程对象 能够获取当前线程的对象
- Thread类
- 概念
from multiprocessing import Process
class MyProcess(Process):
def __init__(self,args):
super().__init__()
self.args = args
def run(self):
print('子进程要执行',self.name)
if __name__ == '__main__':
p = MyProcess(1)
p.start()
p.name
p2 = MyProcess(2)
p2.start()
p2.name
threading.enumerate方法
from threading import enumerate,Thread
def func():
print('in son thread')
Thread(target=func).start()
print(enumerate()) * 返回一个存储着所有线程对象的列表
active_count = len(enumerate())
[<_MainThread(MainThread, started 1200)>,
<Thread(Thread-1, started 4156)>]
守护线程
import time
from threading import Thread
def daemon_func():
while True:
time.sleep(0.5)
print('守护线程')
def son_func():
print('start son')
time.sleep(5)
print('end son')
t = Thread(target=daemon_func)
t.daemon = True
t.start()
Thread(target=son_func).start()
time.sleep(3)
print('主线程结束')
- 主线程会等待子线程的结束而结束
- 守护线程会随着主线程的结束而结束
守护线程会守护主线程和所有的子线程
进程会随着主线程的结束而结束
问题
- 1.主线程需不需要回收子线程的资源
- 不需要,线程资源属于进程,所以进程结束了,线程的资源自然就被回收了
- 2.主线程为什么要等待子线程结束之后才结束
- 主线程结束意味着进程进程,进程结束,所有的子线程都会结束
- 要想让子线程能够顺利执行完,主线程只能等
- 3.守护线程到底是怎么结束的
- 主线程结束了,主进程也结束,守护线程被主进程的结束结束掉了
守护进程 :只会守护到主进程的代码结束
守护线程 :会守护所有其他非守护线程的结束
线程锁
线程里有必要要锁么? 有
GIL和锁的关系
from dis import dis
from threading import Thread,Lock
count = 0
def add_func(lock):
global count
for i in range(200000):
with lock:
count += 1
def sub_func(lock):
global count
for i in range(200000):
with lock:
count -= 1
lst = []
def func(lock):
lst.append(1)
dis(func)
t_l = []
lock = Lock()
for i in range(5):
t1 = Thread(target=add_func,args=(lock,))
t1.start()
t_l.append(t1)
t2 = Thread(target=sub_func,args=(lock,))
t2.start()
t_l.append(t2)
for t in t_l : t.join()
print(count)
- 数据不安全问题
- 在线程中也是会出现数据不安全的
- 1.对全局变量进行修改
- 2.对某个值 += -= *= /=
- 通过加锁来解决
list pop append extend insert remove
dict pop update
list[0] += 1
dic[key] -= 1
list pop/append pop列表为空的时候会报错
queue put/get get队列为空的时候会等待
科学家吃面-死锁
from threading import Lock,Thread
noodle_lock = Lock()
fork_lock = Lock()
def eat1(name):
noodle_lock.acquire() # 阻塞 宝元等面
print('%s拿到面了'%name)
fork_lock.acquire()
print('%s拿到叉子了' % name)
print('%s吃面'%name)
fork_lock.release()
print('%s放下叉子了' % name)
noodle_lock.release()
print('%s放下面了' % name)
def eat2(name):
fork_lock.acquire() # 阻塞 wusir等叉子
print('%s拿到叉子了' % name)
noodle_lock.acquire()
print('%s拿到面了'%name)
print('%s吃面'%name)
noodle_lock.release()
print('%s放下面了' % name)
fork_lock.release()
print('%s放下叉子了' % name)
Thread(target=eat1,args = ('alex',)).start()
Thread(target=eat2,args = ('wusir',)).start()
Thread(target=eat1,args = ('baoyuan',)).start()
快速的解决问题
递归锁
from threading import RLock,Lock
lock = Lock()
rlock =RLock()
rlock.acquire()
print(123)
rlock.acquire()
print(456)
rlock.acquire()
rlock.acquire()
rlock.acquire()
rlock.acquire()
print(789)
rlock.release()
rlock.release()
rlock.release()
rlock.release()
rlock.release()
rlock.release()
from threading import RLock,Thread
fork_lock = noodle_lock = RLock()
def eat1(name):
noodle_lock.acquire() # 阻塞 宝元等面
print('%s拿到面了'%name)
fork_lock.acquire()
print('%s拿到叉子了' % name)
print('%s吃面'%name)
fork_lock.release()
print('%s放下叉子了' % name)
noodle_lock.release()
print('%s放下面了' % name)
def eat2(name):
fork_lock.acquire() * 阻塞 wusir等叉子
print('%s拿到叉子了' % name)
noodle_lock.acquire()
print('%s拿到面了'%name)
print('%s吃面'%name)
noodle_lock.release()
print('%s放下面了' % name)
fork_lock.release()
print('%s放下叉子了' % name)
Thread(target=eat1,args = ('alex',)).start()
Thread(target=eat2,args = ('wusir',)).start()
Thread(target=eat1,args = ('baoyuan',)).start()
互斥锁
from threading import Lock,Thread
lock = Lock()
def eat1(name):
lock.acquire() * 阻塞 宝元等面
print('%s拿到面了'%name)
print('%s拿到叉子了' % name)
print('%s吃面'%name)
print('%s放下叉子了' % name)
print('%s放下面了' % name)
lock.release()
def eat2(name):
lock.acquire() * 阻塞 wusir等叉子
print('%s拿到叉子了' % name)
print('%s拿到面了'%name)
print('%s吃面'%name)
print('%s放下面了' % name)
print('%s放下叉子了' % name)
lock.release()
Thread(target=eat1,args = ('alex',)).start()
Thread(target=eat2,args = ('wusir',)).start()
Thread(target=eat1,args = ('baoyuan',)).start()
- gil 保证线程同一时刻只能一个线程访问CPU,不可能有两个线程同时在CPU上执行指令
- lock 锁 保证某一段代码 在没有执行完毕之后,不可能有另一个线程也执
队列
from queue import Queue
#Queue就是一个线程队列的类,自带lock锁,实现了线程安全的数据类型
#队列是一个线程安全的数据类型
q = Queue() * 先进先出队列
* 在多线程下都不准
* q.empty() 判断是否为空
* q.full() 判断是否为满
* q.qsize() 队列的大小
q.put({1,2,3})
q.put_nowait('abc')
print(q.get_nowait())
print(q.get())
#先进后出的队列 last in first out
from queue import LifoQueue 线程安全的队列 栈和后进先出的场景都可以用
lfq = LifoQueue()
lfq.put(1)
lfq.put('abc')
lfq.put({'1','2'})
print(lfq.get())
print(lfq.get())
print(lfq.get())
from queue import PriorityQueue * 优先级队列
pq = PriorityQueue()
pq.put((10,'askdhiu'))
pq.put((2,'asljlg'))
pq.put((20,'asljlg'))
print(pq.get())
print(pq.get())
print(pq.get())
池
1000个螺丝 1000个任务
制作设备只有4个 CPU的个数
顾几个人? 开多少个进程
import os
import time
from concurrent.futures import ProcessPoolExecutor
def make(i):
time.sleep(1)
print('%s 制作螺丝%s'%(os.getpid(),i))
return i**2
if __name__ == '__main__':
p = ProcessPoolExecutor(4) # 创建一个进程池
for i in range(100):
p.submit(make,i) # 向进程池中提交任务
p.shutdown() # 阻塞 直到池中的任务都完成为止
print('所有的螺丝都制作完了')
p.map(make,range(100)) # submit的简便用法
接收返回值
ret_l = []
for i in range(100):
ret = p.submit(make,i)
ret_l.append(ret)
for r in ret_l:
print(r.result())
ret = p.map(make, range(100))
for i in ret:
print(i)
回调函数
import time
import random
def func1(n):
time.sleep(random.random())
print('in func1 %s'%n)
return n*2
def call_back(arg):
print(arg.result())
if __name__ == '__main__':
p = ProcessPoolExecutor(4)
for i in range(10):
ret = p.submit(func1,i)
ret.add_done_callback(call_back)
ret_l = []
for i in range(10):
ret = p.submit(func1, i)
ret_l.append(ret)
for r in ret_l:
call_back(r)
- 不能有多少个任务就开多少个进程,这样开销太大了
- 用有限的进程执行无限的任务,多个被开启的进程重复利用,节省的是开启\销毁\多个进程切换的时间
- 回调函数是谁执行的?(主进程?子进程)
总结
- 守护线程
- 锁
- 互斥
- 递归
- 死锁现象
- 队列 线程安全的数据类型
- 先进先出
- 后进先出
- 优先级队列
- 池
- 控制进程的数量
- 节省资源开销
最新文章
- Android欢迎界面
- 用C#实现的内存映射
- 安装一些包管理的记录 win10
- 完美演绎DevExpress XtraPrinting Library 的打印功能
- [Java] xms xmx XX:PermSize XX:MaxPermSize 参数意义解析
- C#中的GDI+图形绘制方法
- java 动态编译
- eclipse中导入项目后中文成乱码解决办法
- wait和waitpid的使用和区别
- Qt之信号连接,你Out了吗?
- 关于google的C++ coding style
- 依赖注入及AOP简述(四)——“好莱坞原则”和依赖注入框架简介 .
- eclipse the user operation is waiting for building workspace"; to complete
- 网易ios 面试
- 【Leetcode】Shortest Palindrome
- pip的安装问题
- WebStorm开发React项目,修代码之后运行的项目不更新
- Ajax_请求get,post案例
- java NIO Buffer 详解(1)
- HDU 6395 Sequence 杜教板子题
热门文章
- VS2017生成带图标的QT项目方法
- c++ switch和case的用法
- android使用smack实现简单登录功能
- mac系统vscode环境配置,以及iTerm2配置Zsh + on-my-zsh shell
- Git常用命令及使用,GitLab/GitHub初探,Git/Svn区别
- mysql权限参考
- printf()、sprintf()、vprintf()、vsprintf()(转)
- 箭头函数里this理解
- Python_Mix*OS模块,序列化模块种的json,pickle
- windows版influxDB安装与配置