2019-04-18-day035-守护线程与池
内容回顾
- 互斥锁
- 在同一个进程中连续锁两次以上会死锁
 
 - 进程的数据共享
- 进程之间可以共享数据
 - 提供共享数据的类是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)
- 不能有多少个任务就开多少个进程,这样开销太大了
 - 用有限的进程执行无限的任务,多个被开启的进程重复利用,节省的是开启\销毁\多个进程切换的时间
 - 回调函数是谁执行的?(主进程?子进程)
 
总结
- 守护线程
 - 锁
- 互斥
 - 递归
 - 死锁现象
 
 - 队列 线程安全的数据类型
- 先进先出
 - 后进先出
 - 优先级队列
 
 - 池
- 控制进程的数量
 - 节省资源开销
 
 
2019-04-18-day035-守护线程与池的更多相关文章
- 2019.04.18 读书笔记 深入string
		
整个.net中,最特殊的就是string类型了,它有着引用类型的特性,又有着值类型的操作方式,最特殊的是,它还有字符串池,一个字符串只会有一个实例(等下就推翻!). 鉴于之前的<==与Equal ...
 - 2019.04.18 第六次训练 【2018-2019 ACM-ICPC, NEERC, Southern Subregional Contest, Qualification Stage】
		
题目链接: https://codeforces.com/gym/101911 又补了set的一个知识点,erase(it)之后it这个地址就不存在了,再引用的话就会RE A: ✅ B: ✅ C: ...
 - java 守护线程整理
		
java中finally语句不走的可能存在system.exit(0)与守护线程 线程sleep采用TimeUnit类 设定线程的名字thread.getcurrentThread().setName ...
 - python_线程的开启、守护线程、锁、死锁、事件、定时器、条件、队列、池
		
0.承上 什么是线程? CPU调度的最小单位. 线程是进程的必要组成单位. 主线程: 程序开始运行的时候,就产生了一个主线进程来运行这个程序. 子线程: 是由主线程开启的其他线程. · 各线程之间的工 ...
 - 子进程回收资源两种方式,僵尸进程与孤儿进程,守护进程,进程间数据隔离,进程互斥锁,队列,IPC机制,线程,守护线程,线程池,回调函数add_done_callback,TCP服务端实现并发
		
子进程回收资源两种方式 - 1) join让主进程等待子进程结束,并回收子进程资源,主进程再结束并回收资源. - 2) 主进程 “正常结束” ,子进程与主进程一并被回收资源. from multipr ...
 - Python并发编程04 /多线程、生产消费者模型、线程进程对比、线程的方法、线程join、守护线程、线程互斥锁
		
Python并发编程04 /多线程.生产消费者模型.线程进程对比.线程的方法.线程join.守护线程.线程互斥锁 目录 Python并发编程04 /多线程.生产消费者模型.线程进程对比.线程的方法.线 ...
 - [19/04/08-星期一] 多线程_线程的优先级(Priority) 和 守护线程(Daemon)
		
一.概念 1. 处于就绪状态的线程,会进入“就绪队列”等待JVM来挑选. 2. 线程的优先级用数字表示,范围从1到10,一个线程的缺省优先级是5. 3. 使用下列方法获得或设置线程对象的优先级. in ...
 - Java多线程-线程的调度(守护线程)
		
本文转自http://www.cnblogs.com/linjiqin/p/3210004.html 感谢作者 守护线程与普通线程写法上基本没啥区别,调用线程对象的方法setDaemon(true), ...
 - java并发编程学习: 守护线程(Daemon Thread)
		
在正式理解这个概念前,先把 守护线程 与 守护进程 这二个极其相似的说法区分开,守护进程通常是为了防止某些应用因各种意外原因退出,而在后台独立运行的系统服务或应用程序. 比如:我们开发了一个邮件发送程 ...
 - Java多线程系列--“基础篇”10之 线程优先级和守护线程
		
概要 本章,会对守护线程和线程优先级进行介绍.涉及到的内容包括:1. 线程优先级的介绍2. 线程优先级的示例3. 守护线程的示例 转载请注明出处:http://www.cnblogs.com/skyw ...
 
随机推荐
- RxJava2
			
原文地址 这可能是最好的RxJava 2.x 入门教程(一) 这可能是最好的RxJava 2.x 入门教程(二) 这可能是最好的RxJava 2.x 入门教程(三) 这可能是最好的RxJava 2.x ...
 - 倍增法求LCA(最近公共最先)
			
对于有根树T的两个结点u.v,最近公共祖先x=LCA(u,v)表示一个结点x,满足x是u.v的祖先且x的深度尽可能大. 如图,根据定义可以看出14和15的最近公共祖先是10, 15和16的最近公共 ...
 - mysql 查询正在执行的进程-亲试ok
			
命令:show processlist 每一列的含义和用途: 第一列 id,不用说了吧,一个标识,你要kill一个语句的时候很有用. 第二列 user列,显示单前用户,如果不是root,这个命令就只显 ...
 - count性能
			
表有主键列,count(1)的效率会稍微高于count(*),count(主键列)效率会高于count(1).表没有主键列,count(1)效率会高于count(*) count(1).count(* ...
 - IntelliJ IDEA激活
			
以前一直使用eclipse,直到后来发现了IntelliJ IDEA,就爱上了它. 不过可惜的是,community版本虽然是免费的,不过功能相对较少,而ultimate版本的又需要花钱.但是我穷啊, ...
 - 基于RabbitMQ rpc实现的主机管理
			
要求: 文件分布: 流程图: import pika import os import socket class Server(object): def __init__(self, queuenam ...
 - windows异步通知I/O模型
			
回声服务器端: #include <stdio.h> #include <stdlib.h> #include <WinSock2.h> #define BUF_S ...
 - git 工作区管理
			
git工作区 git的工作区就是电脑中能看到的目录,比如我的learning文件夹就是一个工作区 版本库暂存区 工作去有一个隐藏的目录.git,这个不算工作区,而是git的版本库 git的版本库中存了 ...
 - GDAL——命令使用专题——gdalinfo命令
			
GDAL——命令使用专题——gdalinfo命令 前言 GDAL(Geospatial Data Abstraction Library)是一个在X/MIT许可协议下的开源栅格空间数据转换库.它利用 ...
 - week8
			
---恢复内容开始--- week8 1.动态导入模块 2.断言 3.ftp 4.socketserver 1.动态导入模块 import importlib a = importlib.import ...