python全栈开发day35-线程、协程
一、线程
1.线程
1)、什么是线程
线程是cpu调度的最小单位
线程是进程的必要组成单位
一个进程里至少含有一个线程
2)、主线程
程序开始运行的视乎,就产生了一个主线程来运行这个程序
3)、子线程
是由主线程开启的其他线程
4)、各线程之间的工作
异步的
数据共享的
5)、GIL Cpython全局解释器锁
Cpython解释器,在同一个进程中的多个线程,每次只能有一个线程可以获得执行CPU的权限。
这是由于Cpython的垃圾回收线程等原因导致
2.线程的开启
# 线程不能在外界的干扰下结束,而是等待程序的执行完毕才结束,主线程要等待子线程的结束而结束。
from threading import Thread,currentThread def t_func():
global n
n -= 1
print(currentThread()) if __name__ == '__main__':
n = 100
t_lst = []
for i in range(100):
t = Thread(target=t_func)
t.start()
t_lst.append(t)
print(t.ident,t.name,t.is_alive())
for t in t_lst:t.join()
print(n)
3.守护线程
# 守护线程,会等待主线程执行完毕才结束,主线程会等待所有子线程结束而结束。
from threading import Thread,currentThread,active_count,enumerate
import time def func1():
time.sleep(3)
print('in func1')
def func2():
while True:
time.sleep(0.5)
print('in func2') if __name__ == '__main__':
Thread(target=func1).start()
t = Thread(target=func2, daemon=True)
# t.setDaemon(True)
# t.daemon = True
t.start()
# print(enumerate())
# print(active_count())
# print(currentThread())
# print(t.getName())
# print(t.setName('zzz'))
# print(t.getName())
print('主线程') # 守护线程:会等待主线程执行完毕而结束,主线程会等待所有子进程结束后才结束
守护进程
4.锁
区别GIL和锁,GIL只是同进程中的不同线程只能有一个线程访问CPU,而互斥锁,是保障数据安全的一种机制,二者不冲突。
from threading import Lock,RLock,Thread # 数据不安全实例,由于global数据共享,导致两个线程可能仅计算完+8,还未写入,就被另一个线程抢到执行
# 权限被赋值为0
# def change_balance(n):
# global balance
# balance += n
# balance -= n
#
#
# def run_thread(n):
# for i in range(150000):
# change_balance(n)
#
#
# balance = 0
# t1 = Thread(target=run_thread, args=(5,))
# t2 = Thread(target=run_thread, args=(8,))
# t1.start()
# t2.start()
# t1.join()
# t2.join()
# print(balance) # 加锁 保障数据安全 def change_balance(n):
global balance
balance += n
balance -= n def run_thread(n):
for i in range(150000):
with lock:change_balance(n) balance = 0
lock = Lock()
t1 = Thread(target=run_thread, args=(5,))
t2 = Thread(target=run_thread, args=(8,))
t1.start()
t2.start()
t1.join()
t2.join()
print(balance)
数据安全加锁
5.死锁和递归锁
互斥锁和递归锁的区别:
#互斥锁在同一个线程中连续acquire一次以上就会死锁
#递归锁在同一个线程中可以连续的acquire多次而不发生死锁
#普遍:递归锁可以代替互斥锁来解决死锁现象
#实际上:递归锁的解决死锁实际上是牺牲了时间和空间的
# 死锁从本质上来说是一种逻辑错误
# 递归锁没有从根本上解决死锁问题
递归锁画图描述:
from threading import Lock
# 互斥锁
# lock = Lock()
# lock.acquire()
# print(123)
# lock.release() from threading import RLock
# 递归锁
# lock = RLock()
# lock.acquire()
# lock.acquire()
# print(123)
# lock.release() # 死锁
# 科学家吃面问题
# import time
# from threading import Thread,Lock
#
# def eat1(name,fork_lock,noodle_lock):
# fork_lock.acquire()
# print('%s拿到叉子了'%name)
# noodle_lock.acquire()
# print('%s拿到面条了' % name)
# print('%s吃面'%name)
# noodle_lock.release()
# fork_lock.release()
#
# def eat2(name,fork_lock,noodle_lock):
# noodle_lock.acquire()
# print('%s拿到面条了' % name)
# time.sleep(1)
# fork_lock.acquire()
# print('%s拿到叉子了' % name)
# print('%s吃面'%name)
# fork_lock.release()
# noodle_lock.release()
#
# fork_lock = Lock()
# noodle_lock = Lock()
# Thread(target=eat1,args=('alex',fork_lock,noodle_lock)).start()
# Thread(target=eat2,args=('wusir',fork_lock,noodle_lock)).start()
# Thread(target=eat1,args=('yuan',fork_lock,noodle_lock)).start()
# Thread(target=eat2,args=('jin',fork_lock,noodle_lock)).start() # 递归锁解决死锁现象
# import time
# from threading import Thread,RLock
#
# def eat1(name,fork_lock,noodle_lock):
# fork_lock.acquire()
# print('%s拿到叉子了'%name)
# noodle_lock.acquire()
# print('%s拿到面条了' % name)
# print('%s吃面'%name)
# noodle_lock.release()
# fork_lock.release()
#
# def eat2(name,fork_lock,noodle_lock):
# noodle_lock.acquire()
# print('%s拿到面条了' % name)
# time.sleep(1)
# fork_lock.acquire()
# print('%s拿到叉子了' % name)
# print('%s吃面'%name)
# fork_lock.release()
# noodle_lock.release()
#
# noodle_lock = fork_lock = RLock()
# Thread(target=eat1,args=('alex',fork_lock,noodle_lock)).start()
# Thread(target=eat2,args=('wusir',fork_lock,noodle_lock)).start()
# Thread(target=eat1,args=('yuan',fork_lock,noodle_lock)).start()
# Thread(target=eat2,args=('jin',fork_lock,noodle_lock)).start() # import time
# from threading import Thread,RLock
#
# def eat1(name,lock):
# lock.acquire()
# print('%s拿到叉子了'%name)
# print('%s拿到面条了' % name)
# print('%s吃面'%name)
# lock.release()
#
# def eat2(name,lock):
# lock.acquire()
# print('%s拿到面条了' % name)
# time.sleep(1)
# print('%s拿到叉子了' % name)
# print('%s吃面'%name)
# lock.release()
#
# noodle_fork_lock = Lock()
# Thread(target=eat1,args=('alex',noodle_fork_lock)).start()
# Thread(target=eat2,args=('wusir',noodle_fork_lock)).start()
# Thread(target=eat1,args=('yuan',noodle_fork_lock)).start()
# Thread(target=eat2,args=('jin',noodle_fork_lock)).start() # 互斥锁和递归锁的区别 *****
# 互斥锁在同一个线程中连续acquire一次以上就会死锁
# 递归锁在同一个线程中可以连续的acquire多次而不发生死锁
# 普遍 :递归锁可以代替互斥锁来解决死锁现象 # 实际上 : 递归锁的解决死锁实际上是牺牲了时间和空间的 ****
# 死锁从本质上来讲是一种逻辑错误
# 递归锁没有从根本上解决死锁问题
6.事件
event.isSet():返回event的状态值;
event.wait():如果 event.isSet()==False将阻塞线程;
event.set(): 设置event的状态值为True,所有阻塞池的线程激活进入就绪状态, 等待操作系统调度;
event.clear():恢复event的状态值为False。
from threading import Thread,Event,currentThread
import time,random def check_mysql():
print('\033[45m[%s]正在检查mysql' % currentThread().getName())
time.sleep(random.randint(0,2))
event.set() def conn_mysql():
count = 1
while not event.is_set():
if count > 3:
raise TimeoutError('链接超时')
print('%s第%s次尝试链接' %(currentThread().getName(),count))
time.sleep(0.5)
count += 1
print('<%s>连接成功' % currentThread().getName()) if __name__ == '__main__':
event = Event()
check = Thread(target=check_mysql)
conn1 = Thread(target=conn_mysql)
conn2 = Thread(target=conn_mysql)
check.start()
conn1.start()
conn2.start()
模拟检查连接mysql的例子
7.定时器
# 可以定时多少时间后开始执行线程中的任务。
from threading import Timer,Thread,currentThread def func(n):
print('in func', currentThread().getName(),'args%s'%n) t = Timer(3,func,args=(1,))
t.start()
print(currentThread().getName())
from threading import Timer,Thread,currentThread
import time def func(n):
print('in func', currentThread().getName(),'args%s'%n) t = Timer(3,func,args=(1,))
t.start()
time.sleep(1)
print(t.is_alive())
print(currentThread().getName())
定时器的例子
8.条件
# 一次放行多少个线程,放完就没有了,顺序通过,
# 在acquire()和release必须一一对应,wait或notify之前必须有acquire()
from threading import Condition,Thread def func(n):
con.acquire()
con.wait()
print('run the thread %s' % n)
con.release() if __name__ == '__main__':
con = Condition()
for i in range(10):
t = Thread(target=func,args=(i,))
t.start() while True:
inp = input('>>>')
if inp == 'q':
break
con.acquire()
con.notify(int(inp))
con.release()
9.队列(和threading模块没关系了)
Queue(),PriorityQueue(),LifoQueue()
import queue
# q = queue.Queue() # 先进先出队列,维护先进先出顺序
# q.put(2)
# q.put(3)
# q.put(4)
# print(q.get())
# print(q.get())
# print(q.get()) # q = queue.LifoQueue() # 后进先出队列,栈
# q.put(2)
# q.put(3)
# q.put(4)
# print(q.get())
# print(q.get())
# print(q.get()) q = queue.PriorityQueue() # 优先级队列,优先级相同,根据ascii码先后 q.put((10, 2))
q.put((20, 3))
q.put((1, 4))
q.put((100, 'b'))
q.put((100, 'a')) print(q.get())
print(q.get())
print(q.get())
print(q.get())
print(q.get())
三种队列举例
10.池
multiprocessing中的Pool:
# apply_async 异步提交任务
# 必须close join之后才能维护主进程和进程池之间的同步
# map自带close、join效果
# 获取执行结果get
# 回调函数 指定callback参数,由主进程执行
concurrent.futures.ThreadPoolExecutor/concurrent.futures.ProcessPoolExecutor
# submit 异步提交任务
# 使用shutdown来维护主进程和进程池之间的同步
# map是不自带shutdown
# 获取执行结果用result
# 回调函数 直接调用add_done_callback方法,由子线程/子进程执行
# 用concurrent.futures,可以轻松的在进程和线程之间切换(代码改个名字即可)
#并发程序,线程池进程池都要用,只需要导入一个模块
# concurrent.futures模块是一个新的模块,同意了线程池和进程池的使用方式,对一些操作进行了更合理的规划。
二、协程
1)、协程--纤程,本质是线程的一部分
2)、对比线程和协程
# 线程,正常的线程,遇到阻塞就停下来,直到阻塞事件结束,才继续执行
# 协程,利用了协程,就把线程分成了好几段,在一个任务出现阻塞的时候,自动切换到另一任务去执行,这些事情在一个线程里面完成。
3)、如果这个程序从头到尾没有IO,没有阻塞,程序根本就不会在多个任务之间切换,就是一个顺序执行的协程,对于高计算型的代码没有用。
4)、协程
# 数据安全的问题不存在了
# 如何调度的呢?
# 操作系统不调度协程
# 用户级别来调度的gevent
# 协程的调度速度比线程还快
# 协程的调度由于是python代码级别而不是操作系统级别,所有用户的可控性更强,降低了操作系统的工作量。
5)、协程到底是怎么实现程序之间的切换的
生成器:
def func():
print(123)
yield 1
print(456)
yield 2
print(789)
yield 3 def wahaha(g):
for i in g:
print(i) g = func()
wahaha(g)
生成器程序之间切换的例子
协程之间的切换:gevent依赖greenlet,协程之间的切换有greenlet完成
# def func():
# print(123)
# yield 1
# print(456)
# yield 2
# print(789)
# yield 3
#
#
# def wahaha(g):
# for i in g:
# print(i)
#
# g = func()
# wahaha(g) # 协程之间的切换 from greenlet import greenlet def eat(name):
print('%s eat 1' %name)
g2.switch('egon')
print('%s eat 2' %name)
g2.switch()
def play(name):
print('%s play 1' %name)
g1.switch()
print('%s play 2' %name) g1 = greenlet(eat)
g2 = greenlet(play) g1.switch('alex')
greenlet
from gevent import monkey
monkey.patch_all()
import time
import gevent # 能够在遇到自己认识的IO操作的时候主动调用greenlet中的switch来切换到其他的任务以提高程序的效率
from threading import currentThread
def eat(name):
print(currentThread())
print('%s eat 1' %name)
time.sleep(2)
print('%s eat 2' %name) def play(name):
print(currentThread())
print('%s play 1' %name)
time.sleep(1)
print('%s play 2' %name) g1=gevent.spawn(eat,'egon') # 就是发布了任务
g2=gevent.spawn(play,name='egon') # 就是发布了任务
# g1.join() # 等待g1任务执行完毕,阻塞,帮助你完成g1中函数的全部内容
# g2.join()
gevent.joinall([g1,g2])
print('主')
gevent
# 效率对比 from gevent import spawn, joinall, monkey;
monkey.patch_all() import time def task(pid):
time.sleep(0.5)
print('Task %s done' % pid) def synchronous(): # 同步
for i in range(10):
task(i) def asynchronous(): # 异步
# g_l = []
# for i in range(10):
# g = spawn(task,i)
# g_l.append(g)
# for g in g_l:g.join()
# joinall(g_l) joinall([spawn(task, i) for i in range(10)]) if __name__ == '__main__':
# print('Synchronous:')
# synchronous()
print('Asynchronous:')
asynchronous()
高IO同步异步效率对比
# 解决并发问题???
# 多进程 高计算型,浪费操作系统和资源,可以利用多核
# 多线程 高IO型,也会给操作系统添加负担,会占用比进程少的资源,
# 受到GIL,不能利用多核
# 协程 高IO型,完全不会给操作系统添加负担,几乎不占资源
# 始终不能利用多核
# 多进程 + 多线程 = 100
# 多进程 + 多线程 + 协程 = 50000/4c
# 4c
# 多进程 CPU+1 = 5
# 多线程 CPU*5 = 20
# 协程 500个协程
python全栈开发day35-线程、协程的更多相关文章
- Python全栈开发:线程、进程和协程
Python线程 Threading用于提供线程相关的操作,线程是应用程序中工作的最小单元. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 #!/usr/bin/env pytho ...
- Python全栈开发:线程代码实例
#进程与线程的关系 """ 多进程(主进程,子进程): 优点:能同时利用多个CPU,进行多个操作,提高效率. 缺点:耗费内存资源(进程要开辟内存空间),进程不是越多越好, ...
- python全栈开发目录
python全栈开发目录 Linux系列 python基础 前端~HTML~CSS~JavaScript~JQuery~Vue web框架们~Django~Flask~Tornado 数据库们~MyS ...
- Python全栈开发【面向对象】
Python全栈开发[面向对象] 本节内容: 三大编程范式 面向对象设计与面向对象编程 类和对象 静态属性.类方法.静态方法 类组合 继承 多态 封装 三大编程范式 三大编程范式: 1.面向过程编程 ...
- Python全栈开发【模块】
Python全栈开发[模块] 本节内容: 模块介绍 time random os sys json & picle shelve XML hashlib ConfigParser loggin ...
- python全栈开发中级班全程笔记(第二模块、第四章)(常用模块导入)
python全栈开发笔记第二模块 第四章 :常用模块(第二部分) 一.os 模块的 详解 1.os.getcwd() :得到当前工作目录,即当前python解释器所在目录路径 impor ...
- python全栈开发学习_内容目录及链接
python全栈开发学习_day1_计算机五大组成部分及操作系统 python全栈开发学习_day2_语言种类及变量 python全栈开发_day3_数据类型,输入输出及运算符 python全栈开发_ ...
- Python 全栈开发【第0篇】:目录
Python 全栈开发[第0篇]:目录 第一阶段:Python 开发入门 Python 全栈开发[第一篇]:计算机原理&Linux系统入门 Python 全栈开发[第二篇]:Python基 ...
- Python全栈开发【面向对象进阶】
Python全栈开发[面向对象进阶] 本节内容: isinstance(obj,cls)和issubclass(sub,super) 反射 __setattr__,__delattr__,__geta ...
- Python全栈开发【基础四】
Python全栈开发[基础四] 本节内容: 匿名函数(lambda) 函数式编程(map,filter,reduce) 文件处理 迭代器 三元表达式 列表解析与生成器表达式 生成器 匿名函数 lamb ...
随机推荐
- 个股和股票池的beta系数的估算
个股的beta系数的估算 代码 def test_gg_beta(symbol='000895.sz', start='2018-01-01', plot_price=True, align_to=' ...
- 词典的实现(1)--Map的底层实现
1,词典是这样的一种数据结构:它能根据给定的键(索引值,key)来查找其对应的值(value)是否存在,在JAVA中主要由java.util.HashMap来完成该功能.如电话本就是词典的一个具体实例 ...
- flash GC
所有应用程序都要管理内存.应用程序的内存管理包括用于确定何时分配内存,分配多少内存,何时将内容放入回收站,以及何时清空回收站的准则.MMgc是 Flash Player用于几乎所有内存分配工作的通用内 ...
- mysql 原理 ~ 事务隔离机制
简介: 事务隔离知多少内容 一 基础知识 1 事务特性 ACID A 原子性 C 一致性 I 隔离性 D 持久性 2 并行事务出现的问题 1 脏读 读取了其他事务未提交的数据 ...
- ROS 时间同步问题
0. 问题 两台ubuntu主机无法与一台debian主机使用分布式通信,摄像头发出的话题机器人收不到,考虑是时间同步的问题. 也可能是系统不统一的问题; 今天在家实验了一下,时间差6min,照样可以 ...
- [Shell]获取IP地址
ifconfig eth0 | grep "inet addr:" | awk '{print $2}' | cut -c 6- ifconfig eth1 | grep &quo ...
- mysql系列十一、mysql优化笔记:表设计、sql优化、配置优化
可以从这些方面进行优化: 数据库(表)设计合理 SQL语句优化 数据库配置优化 系统层.硬件层优化 数据库设计 关系数据库三范式 1NF:字段不可分; 2NF:有主键,非主键字段依赖主键; 3NF:非 ...
- git强制覆盖更新
1.选择项目,右键选择Team,选择Team里面的Reset. 2.点击Reset后弹出Reset窗口,选择Hard选项,这样就会把远端的项目完全拉下来覆盖本地,本地没有的文件也会被创建,点击确定.
- Vue.js——component(组件)
概念: 组件(Component)是自定义元素. 作用: 可以扩展HTML元素,封装可重用的代码. <div id="myView"> <!-- 把学生的数据循环 ...
- html的结构-厂子型的布局
上图所示的布局设计是很常见的.这个该怎么做呢? 技术需求:header 要固定住在顶部,不随鼠标滚动而向上移动:左边的div的有一定的宽度,但是要贴浏览器的底部(屏幕顶部):右边的dv要占据右边的全屏 ...