python并发编程之协程
---恢复内容开始---
一、join方法
(1)开一个主线程
from threading import Thread,currentThread
import time
def walk():
print('%s is running'%currentThread().getName())
time.sleep(2)
print('%s is done'%currentThread().getName())
if __name__ == '__main__':
# for i in range(10):
p=Thread(target=walk)
p.start()
p.join()
print('主') #主线程在等p.join执行
开一个主线程
(2)开多个主线程,并发运行
from threading import Thread,currentThread
import time
def walk():
print('%s is running'%currentThread().getName())
time.sleep(2)
print('%s is done'%currentThread().getName())
if __name__ == '__main__':
l=[]
for i in range(10):
p=Thread(target=walk)
l.append(p)
p.start()
# p.join() #在p.start() 跟p.join()就会变为串行,一个一个的运行
for p in l:
p.join()
print('主')
开多个主线程
(3)并发运行 互斥锁之锁局部的 ,用所只锁住你对共享数据修改的部分
加锁:
from threading import Thread,currentThread,Lock
import time
n=100
def walk():
# 并发运行
time.sleep(2)
global n
mutex.acquire()
# 串行
temp=n
time.sleep(0.01)
n=temp-1 #数据可能同是减1,可能数据会乱
mutex.release()
if __name__ == '__main__':
mutex=Lock()
l=[]
start = time.time()
for i in range(100):
p=Thread(target=walk)
l.append(p)
p.start()
for p in l:
p.join()
stop = time.time()
print('n:%s run_time : %s' %(n,stop - start))
不加锁:
from threading import Thread,currentThread,Lock
import time
n=100
def walk():
time.sleep(2)
global n
# mutex.acquire()
temp=n
time.sleep(0.1)
n=temp-1 #数据可能同是减1,可能数据会乱
# mutex.release()
if __name__ == '__main__':
mutex=Lock()
start = time.time()
for i in range(10):
p=Thread(target=walk)
p.start()
p.join()
stop = time.time()
print('n:%s run_time : %s' %(n,stop - start)) #至少21秒
并发运行,不加锁
主线程运行完毕是在所有线程所在的进程内所有非守护线程运行完毕才运行
二、GIL本质是一把互斥锁,将并发转成串行,以此来控制同一时间内共享数据只能被一个任务修改,
进而保证数据的安全
from threading import Thread,currentThread,Lock
import time
n=100
def work():
time.sleep(2)
global n
time.sleep(0.5)
mutex.acquire()
temp=n
time.sleep(0.1)
n=temp-1
mutex.release()
if __name__ == '__main__':
mutex=Lock()
t1=Thread(target=work)
t2=Thread(target=work)
t3=Thread(target=work)
t1.start()
t2.start()
t3.start()

三、多线程性能测试
(1)'''
多进程
优点:可以利用多核
缺点:开销大 多线程
优点:开销小
缺点:不可以利用多核
'''
from multiprocessing import Process
from threading import Thread
import time
def work():
res=0
for i in range(10000000):
res+=i if __name__ == '__main__':
l=[]
start=time.time()
for i in range(4):
# p=Process(target=work) #0.9260530471801758
p=Thread(target=work) #0.9260530471801758
l.append(p)
p.start() for p in l:
p.join() stop=time.time()
print('%s' %(stop-start))
计算机密集型--开启多进程
from multiprocessing import Process
from threading import Thread
import time
def work():
time.sleep(2) if __name__ == '__main__':
l=[]
start=time.time()
for i in range(400):
p=Process(target=work)
# p=Thread(target=work)
l.append(p)
p.start() for p in l:
p.join() stop=time.time()
print('%s' %(stop-start))
I/O密集型---开启多线程
(2)应用:
多线程用于IO密集型,如socket,爬虫,web
多进程用于计算密集型,如金融分析
四、死锁与递归锁
死锁:
from threading import Thread,RLock
import time
mutexA=RLock()
class MyThread(Thread):
def run(self):
self.f1()
self.f2()
def f1(self):
mutexA.acquire()
print('%s 拿到A锁'%self.name)
mutexA.acquire()
print('%s 拿到B锁' % self.name)
mutexA.release()
mutexA.release()
def f2(self):
mutexA.acquire()
print('%s 拿到A锁' % self.name)
time.sleep(1)
mutexA.acquire()
print('%s 拿到B锁' % self.name)
mutexA.release()
mutexA.release()
if __name__ == '__main__':
for i in range(10):
t=MyThread()
t.start()
解决死锁的方法
递归锁:用RLock代替Lock
from threading import Lock,Thread,RLock
import time
# mutexA=Lock()
# mutexB=Lock()
mutexB=mutexA=RLock()
class MyThread(Thread):
def run(self):
self.f1()
self.f2()
def f1(self):
mutexA.acquire()
print('\033[32m%s 拿到A锁' %self.name)
mutexB.acquire()
print('\033[45m%s 拿到B锁' %self.name)
mutexB.release()
mutexA.release()
def f2(self):
mutexB.acquire()
print('\033[32m%s 拿到B锁' %self.name)
time.sleep(1)
mutexA.acquire()
print('\033[45m%s 拿到A锁' %self.name)
mutexA.release()
mutexB.release()
if __name__ == '__main__':
for i in range(10):
t=MyThread()
t.start()
递归锁
五、信号量
信号量和进程一样
信号量就是一把锁,可以有多把钥匙
from threading import Thread,Semaphore,currentThread
import time,random
sm=Semaphore(5)
def task():
sm.acquire()
print('%s 上厕所' %currentThread().getName())
time.sleep(random.randint(1,3))
print('%s 走了' %currentThread().getName())
sm.release()
if __name__ == '__main__':
for i in range(20):
t=Thread(target=task)
t.start()
六、事件
Event
vent.isSet():返回event的状态值;
event.wait():如果 event.isSet()==False将阻塞线程;
event.set(): 设置event的状态值为True,所有阻塞池的线程激活进入就绪状态, 等待操作系统调度;
event.clear():恢复event的状态值为False。
from threading import Thread,currentThread,Event
import time
e=Event()
def traffic_ligths():
time.sleep(1)
e.set()
def car(): print('\033[45m%s等'%currentThread().getName())
e.wait()
print('\033[43m%s开'%currentThread().getName())
if __name__ == '__main__':
print('绿灯')
for i in range(10):
p=Thread(target=car)
p.start()
# print('绿灯')
time.sleep(5)
print('红灯')
traffic_ligth=Thread(target=traffic_ligths)
traffic_ligth.start()
红绿灯事列
from threading import Thread, currentThread, Event
import time
e = Event()
def conn_mysql():
count = 1
while not e.is_set():
if count > 3:
raise ConnectionError('尝试链接的次数太多了')
print('\033[45m%s 第%s次尝试' % (currentThread().getName(), count))
e.wait(timeout=1)
count += 1
print('\033[45m%s 开始链接' %currentThread().getName())
def check_myql():
print('\033[45m%s 开始检测 my_sql....' %currentThread().getName())
time.sleep(2)
e.set()
if __name__ == '__main__':
for i in range(2):
p = Thread(target=conn_mysql)
p.start()
p = Thread(target=check_myql)
p.start()
链接——sql
七、定时器
定时器,是n秒后执行操作
rom threading import Timer def hello(n):
print("hello, world",n) t = Timer(3, hello,args=(123,))
t.start() # after 1 seconds, "hello, world" will be printed
定时器
八、线程queue
queue队列,用法与进程queue一样
q=queue.queue() 先进先出
q=queue.Queue(3) #先进先出
q.put('first')
q.put('second')
q.put('third')
# q.put('fourth') print(q.get())
print(q.get())
print(q.get())
q=queue.LifoQueue() 先进后出
q=queue.LifoQueue() #先进后出
q.put('first')
q.put('second')
q.put('third')
# q.put('fourth') print(q.get())
print(q.get())
print(q.get())
put进入一个元组,元组的第一个元素是优先级(通常是数字,也可以是非数字之间的比较),数字越小优先级越高
import queue
q=queue.PriorityQueue()
q.put((20,'a'))
q.put((10,'b'))
q.put((30,'c'))
print(q.get())
print(q.get())
print(q.get())
---恢复内容结束---
python并发编程之协程的更多相关文章
- python并发编程之协程知识点
由线程遗留下的问题:GIL导致多个线程不能真正的并行,CPython中多个线程不能并行 单线程实现并发:切换+保存状态 第一种方法:使用yield,yield可以保存状态.yield的状态保存与操作系 ...
- 32 python 并发编程之协程
一 引子 本节的主题是基于单线程来实现并发,即只用一个主线程(很明显可利用的cpu只有一个)情况下实现并发,为此我们需要先回顾下并发的本质:切换+保存状态 cpu正在运行一个任务,会在两种情况下切走去 ...
- 四 python并发编程之协程
一 引子 本节的主题是基于单线程来实现并发,即只用一个主线程(很明显可利用的cpu只有一个)情况下实现并发,为此我们需要先回顾下并发的本质:切换+保存状态 cpu正在运行一个任务,会在两种情况下切走去 ...
- python并发编程之协程(实践篇)
一.协程介绍 协程:是单线程下的并发,又称微线程,纤程.一句话说明什么是线程:协程是一种用户态的轻量级线程,即协程是由用户程序自己控制调度的. 对于单线程下,我们不可避免程序中出现io操作,但如果我们 ...
- 第十篇.5、python并发编程之协程
一 引子 本节的主题是基于单线程来实现并发,即只用一个主线程(很明显可利用的cpu只有一个)情况下实现并发,为此我们需要先回顾下并发的本质:切换+保存状态 cpu正在运行一个任务,会在两种情况下切走去 ...
- 第 12 章 python并发编程之协程
一.引子 主题是基于单线程来实现并发,即只用一个主线程(很明显可利用的cpu只用一个)情况下实现并发,并发的本质:切换+保存状态 cpu正在运行一个任务,会在两种情况下切走去执行其他的任务(切换由操作 ...
- 37、python并发编程之协程
目录: 一 引子 二 协程介绍 三 Greenlet 四 Gevent介绍 五 Gevent之同步与异步 六 Gevent之应用举例一 七 Gevent之应用举例二 一 引子 本节的主题是基于单线程来 ...
- python 并发编程之协程
一.协程 协程: 单线程下的并发,又称 微线程.协程是一种用户态的的轻量级线程,即协程是由用户程序自己控制调度的. 协程的本质就是在单线程下,由用户自己控制一个任务,遇到 io 阻塞就切换另外一个 ...
- python全栈开发从入门到放弃之socket并发编程之协程
一.为什么会有协程 本节的主题是基于单线程来实现并发,即只用一个主线程(很明显可利用的cpu只有一个)情况下实现并发,为此我们需要先回顾下并发的本质:切换+保存状态 cpu正在运行一个任务,会在两种情 ...
随机推荐
- 提升tomcat服务器性能的七条经验
在线上环境中我们是采用了tomcat作为Web服务器,它的处理性能直接关系到用户体验,在平时的工作和学习中,归纳出以下七种调优经验. 1. 服务器资源 服务器所能提供CPU.内存.硬盘的性能对处理能力 ...
- APP软件半成品测试技巧
由于现在产品类型的多样性,产品功能的先进性,更多体现在产品质量的稳定性和可靠性.软件应用的领域不断深入,设计的复杂程度逐步扩大,开发的周期不断缩短,质量的要求就逐渐提高.然而根据我们公司的版本迭代速度 ...
- JavaScript的8行代码搞定js文件引入问题
单页面的操作,免不了会有各种jsp的嵌套问题,一个操作页面里面可能涉及到几十甚至上百个jsp页面. 平常我们对用到的js文件的引入,都会放到index的header里面.如图: 但是,让我们思考三个问 ...
- LAMP环境的搭建(二)----Mysql安装与配置
Mysql是一款免费开源的关系型数据库. 尽管Mysql被oracle公司收购.但是oracle并没有限制了mysql的发展. 目前mysql是使用范围最广的关系型数据库,许多大型公司也在使用.截至本 ...
- SpringMVC基础-@RequestMapping
@RequestMapping @RequestMapping是一个用来处理请求地址映射的注解 可用于类或方法上. 类定义处:提供初步的请求映射信息.相当于当前 WEB 应用的根目录 方法处: ...
- php sql uuid 32位
最近表中id需要用到此值来作为唯一主键 其含义是通用唯一识别码.具体好处及应用可百度百科,链接给你https://baike.baidu.com/item/UUID/5921266?fr=aladdi ...
- 迈向angularjs2系列(6):路由机制
目录1.angular-seed的路由2.路由机制的探索3.懒加载 一:angular-seed的路由 step1:安装种子项目 $ git clone --depth 1 https://gi ...
- python自学1——代码优化1
优化了上次的代码,请求方式可接收get和post两种,代码中对两种方式做了判断. 测试结果中提取了测试用例的名称.请求返回的状态.请求的时间. #coding:utf-8 import xlrd im ...
- Redis订阅和发布模式和Redis事务
-------------------Redis订阅和发布模式------------------- 1.概念 Redis 发布订阅(pub/sub)是一种消息通信模式: 发送者(pu ...
- P问题、NP问题、NPC问题
看师兄们的论文经常说一句这是个NP难问题,所以采用另外一种方法来代替(比如凸松弛,把l0范数的问题松弛为l1范数的问题来求解).然后搜索了相关知识,也还是没看太懂,把一些理论知识先贴上来,希望以后再接 ...