Python 多道技术以及进程、线程和协程
多道技术
并发:看起来像同时运行
并行:真正意义上的同时运行,并行肯定是并发
空间的复用与时间复用
- 空间复用
多个程序用一套计算机硬件
- 时间复用
程序切换节省时间
'''
切换(cup)分为两种情况
1.当一个程序遇到IO操作的时候,操作系统会剥夺该程序的CPU执行权限
作用:提高CPU的利用率,并且不影响程序的执行效率
2.当一个程序长时间占用CPU的时候,操作吸引也会剥夺该程序的CPU执行权限
弊端:降低程序的执行效率(原本时间+切换时间)
'''
进程
程序与进程的区别
程序是一堆代码,保存在硬盘上,是“死”的。
进程表示的是程序正在执行的过程,是”活“的。
进程的调度
- 先来先服务调度算法
- 短作业优先调度算法
- 时间片轮转法+多级反馈队列
进程三状态图
两对重要概念
同步和异步
描述的是任务的提交方式
- 同步:任务提交后,原地等待任务的返回结果,等待的过程不做任何事情(程序层面上表现出来感觉就是卡住了)
- 异步:任务提交之后,不原地等待任务的返回结果,直接去做其他事情。任务的返回结果会有一个异步回调机制自动处理。
阻塞和非阻塞
描述的程序的运行状态
- 阻塞:阻塞态
- 非阻塞:非阻塞态
理想状态:代码永远处于就绪态和运行态之间切换
上述概念的组合:最高效的一种组合就是异步非阻塞
开启进程的两种方式
代码开启进程和线程的方式是一样的。
第一种方式
# 第一种方式 类实例化产生对象
from multiprocessing import Process
import time
def task(name):
print('%s is running'%name)
time.sleep(3)
print('%s is over'%name)
if __name__ == '__main__':
# 1.创建一个对象
p = Process(target=task,args=('hp',))
# 容器类型哪怕里面只有一个元素都要用逗号隔开
# 2.开启进程
p.start() #告诉操作系统创建一个进程 异步
print('***********')
'''
windows操作系统下 创建进程一定要在main内创建
因为windows下创建进程类似于模块导入的方式
会从上往下依次执行代码
在linux中,直接将代码完整拷贝一份
'''
第二种方式
# 第二种方式 类的继承
from multiprocessing import Process
import time
class MyProcess(Process):
def run(self):
print('hello bf girl')
time.sleep(1)
print('get out')
if __name__ == '__main__':
p = MyProcess()
p.start()
print('***********')
总结
'''
创建进程就是在内存中申请一块内存空间将需要运行的代码丢进去
一个进程对应在内存中就是一块内存空间
多个进程对应在内存中就多快独立的内存空间
进程与进程之间数据默认情况下就是无法之间交互,如果想交互可以借助第三方工具、模块
'''
join方法
join是让主进程等待子进程代码运行结束之后,再继续运行。不影响其他子进程运行。
from multiprocessing import Process
import time
def task(name,n):
print('%s is running'%name)
time.sleep(n)
print('%s is over'%name)
if __name__ == '__main__':
start_time = time.time()
# # 1.创建一个对象
# p1 = Process(target=task,args=('hp',1))
# p2 = Process(target=task, args=('hp',2))
# p3 = Process(target=task, args=('hp',3))
# # 2.开启进程
# p1.start() #告诉操作系统创建一个进程 异步
# p2.start()
# p3.start()
# p1.join() # 主进程等待子进程p运行结束之后再继续执行
# p2.join()
# p3.join()
p_list = []
for i in range(1,4):
p = Process(target=task, args=('hp', i))
p.start()
p_list.append(p) #先全部开启进程
#p.join() # 6秒多
for p in p_list: #通过for循环同时运行进程
p.join() # 3秒多
print('***********',time.time()-start_time)
进程数据相互隔离(默认情况下)
from multiprocessing import Process
money = 100
def tack():
global money
money = 666
print('子进程:%s'%money)
if __name__ == '__main__':
p = Process(target=tack)
p.start()
p.join()
print('主进程:%s'%money)
#输出结果
子进程:666
主进程:100
进程对象以及其他方法
'''
一台计算机上面运行着很多进程,那么计算机是如何区分并管理这些进程服务端的呢?
计算机会给每一个运行的进程分配一个PID号
如何查看
windows电脑 cmd输入tasklist即可查看
tasklist |findstr PID查看具体的进程
mac电脑 进入终端ps aux
ps aux|grep PID查看具体进程
'''
from multiprocessing import Process,current_process
current_process().pid #查看当前的进程号
import os
os.getpid() #查看当前的进程号
os.getppid() #查看当前进程的父进程号
守护进程
父进程结束守护进程也结束。
from multiprocessing import Process
import time
def tack(name):
print('%s总管正在存活' % name)
time.sleep(3)
print('%s总管正在死亡' % name)
if __name__ == '__main__':
p = Process(target=tack,args=('Hp',))
p.daemon = True # 将进程p设置成守护进程,一定要放在p.start上面才有效,否则直接报错
p.start()
print('皇帝寿终正寝')
# 输出结果:
皇帝寿终正寝
互斥锁
多个进程操作同一份数据的时候,会出现数据错乱的问题
解决方式:加锁处理
加锁处理:将并发变成串行,牺牲效率但是保证数据的安全
from multiprocessing import Process, Lock # 互斥锁
import json
import time
import random
# 查票
def search(i):
# 文件操作读取票数
with open('data','r',encoding='utf-8') as f:
dic = json.load(f) # json.load()从文件中读取json字符串
print('用户%s查询余票:%s' %(i,dic.get('ticket_num')))
# 字典取值不要用[]的形式,推荐使用get
# 买票 1.查票 2.买票
def buy(i):
# 先查票
with open('data','r',encoding='utf-8') as f:
dic = json.load(f)
# 模拟网络延迟
time.sleep(random.randint(1,3))
# 判断当前是否有票
if dic.get('ticket_num') > 0:
# 修改数据库买票
dic['ticket_num'] -= 1
# 写入数据库
with open('data','w',encoding='utf-8') as f:
json.dump(dic,f) # json.dump()是通过文件的形式进行处理
print('用户%s买票成功'%i)
else:
print('用户%s购票失败'%i)
# 整合上面两个函数
def run(i, mutex):
search(i)
# 给买票环节加锁处理
# 抢锁
mutex.acquire()
buy(i)
# 释放锁
mutex.release()
if __name__ == '__main__':
# 在主进程中生成一把锁 让所有子进程抢,谁先抢到谁就先买
mutex = Lock()
for i in range(1,10):
p = Process(target=run,args=(i, mutex))
p.start()
'''
扩展:行锁 表锁
注意:
1.锁不要轻易的使用,容易造成死锁现象(写代码的时候一般不会用到,都是内部封装好的)
2.锁只在处理数据的部分加来保证数据安全(只在争抢数据的环节加锁处理)
'''
进程间通信
队列Queue模块
管道:subprocess
stdin stdout stderr
队列:先进先出,管道+锁
堆栈:先进后出
import queue
# 创建队列
q = queue.Queue(5) # 括号内可以传数字 表示生成队列最大可以同时存放的数据量
# 往队列中存放数据
q.put(111)
q.put(222)
q.put(333)
# print(q.full()) # 判断当前队列是否满了
# print(q.empty()) # 判断当前队列是否空了
q.put(444)
q.put(555)
# print(q.full())
# q.put(666) # 当队列数据放满之后 如果还有数据会阻塞 直到有位置让出来
# 去队列中取数据
v1 = q.get()
v2 = q.get()
v3 = q.get()
v4 = q.get()
v5 = q.get()
# v6 = q.get_nowait() # 没有数据直接报错 queue.Empty
# v6 = q.get(timeout=3) # 没有数据原地等待3秒之后再报错 queue.Empty
# v6 = q.get() # 队列中如果没有数据 get方法会原地阻塞
try:
v6 = q.get(timeout=3)
print(v6)
except Exception as e:
print('没有了')
# print(v1,v2,v3,v4,v5,)
'''
q.full()
q.empty()
q.get_nowait()
在多进程的情况下是不精确的
'''
IPC机制
IPC机制的含义是进程间通信或者跨进程通信,是指两个进程之间进行数据交换。
from multiprocessing import Queue, Process
'''
研究思路
1.主进程跟子进程借助于队列通信
2.子进程跟子进程借助于队列通信
'''
def producer(q):
q.put('hello word') # 向队列存入 hello word
# print('hello big baby')
def consumer(q):
print(q.get()) #向队列中取出数据
if __name__ == '__main__':
q = Queue()
p = Process(target=producer,args=(q,))
p1 = Process(target=consumer,args=(q,))
p.start()
p1.start()
# print(q.get())
生产者消费者模型
生产者:生产/制作东西
消费者:消费/处理东西
该模型除了上述两个之外还需要一个媒介
生产者和消费者之间不是直接做交互的,而是借助于媒介做交互
生产者 + 消息队列 +消费者
from multiprocessing import Queue, Process, JoinableQueue
import time
import random
def property(name, food, q):
for i in range(4):
data = '%s生产了%s%s'% (name, food, i)
# 模拟延迟
time.sleep(random.randint(1,3))
print(data)
# 将数据放入队列中
q.put(data)
def consumer(name,q):
# 全部处理
while True:
food = q.get()
# 判断当前是否有结束标记
# if food is None:break
time.sleep(random.randint(1,3))
print('%s吃了%s' % (name,food))
q.task_done() # 告诉队列已经从里面取出一个数据并且处理完毕
if __name__ == '__main__':
# q = Queue()
q = JoinableQueue()
p1 = Process(target=property,args=('大厨', '凉拌青瓜', q))
p2 = Process(target=property,args=('Hp', '泰式鸡爪', q))
c1 = Process(target=consumer,args=('sj',q))
p1.start()
p2.start()
# 将消费者设置成守护进程
c1.daemon = True
c1.start()
p1.join()
p2.join()
# 等生产者生产完毕之后 往队列中添加特定的结束符号
# q.put(None) # 使用Queue()的时候,在所有生产者生产的数据的末尾加上结束符号
q.join() # 等待队列中所有的数据被取完再往下执行
'''
JoinableQueue 每当你往该队列中存入数据的时候,内部会有一个计数器+1
每当你调用task_done的时候 计数器-1
q.join() 当计数器为0的时候才往下运行
'''
# 只有q.join执行完毕 说明消费者已经处理完数据,消费者没必要存在了
线程
什么是线程
'''
进程:资源单位(起一个进程仅仅只是在内存空间中开辟一块独立的空间)
线程:执行单位(真正被CPU执行的其实是进程里面的线程,线程指的是代码的执行过程,执行代码中所需要使用到的资源都找所在的进程索要)
每一个进程肯定带一个线程
进程和线程都是虚拟单位,只是为了更加方便的描述问题
'''
为何要有线程
'''
开设进程
1.申请内存空间 耗资源
2.“拷贝代码” 耗资源
开线程
一个进程内可以开设多个线程,在用一个进程内开设多个线程无需再次申请内存空间操作
总结:
开设线程的开销远远小于进程的开销
同一个进程下的多个线程都是共享的
'''
如何使用
开启线程的两种方式
# 第一种方式 类的实例化对象
from multiprocessing import Process
from threading import Thread
import time
def task(name):
print('%s is running' % name)
time.sleep(1)
print('%s is over' % name)
'''
开启线程不需要在main下面书写代码,直接书写就可以
但是还是习惯性将启动命令写在main下面
'''
t = Thread(target=task,args=('hp',))
# p = Process(target=task,args=('sj',))
# p.start()
t.start() # 创建线程的开销非常小 几乎代码一执行线程就已经创建了
print('主')
# 第二种方式 类的继承
from threading import Thread
import time
class MyThread(Thread):
def __init__(self, name):
# 重写别的方法,调用父类的方法
super().__init__()
self.name = name
def run(self):
print('%s is running' % self.name)
time.sleep(1)
print('%s is over'% self.name)
if __name__ == '__main__':
t = MyThread('hp')
t.start()
print('主线程')
TCP服务端实现并发效果
import socket
from threading import Thread
from multiprocessing import Process
'''
服务端
1.固定的IP和端口
2.24小时不间断提供服务
3.支持并发
'''
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #括号内不加参数默认TCP协议
server.bind(('127.0.0.1',8080)) #绑定连接
server.listen(5) #指的是半连接池的大小
# 将服务代码单独封装成一个函数
def talk(conn):
# 通信循环
while True:
try:
data = conn.recv(1024)
# 针对mac linux 客户端断开链接
if len(data) == 0: break
print(data.decode('utf-8'))
conn.send(data.upper())
except Exception as e:
print(e)
break
conn.close()
# 链接循环
while True:
conn, addr = server.accept() #接客
# 其他人服务客户
t = Thread(target=talk,args=(conn,))
t.start()
线程对象的join方法
from threading import Thread
import time
def task(name):
print('%s is running' % name)
time.sleep(1)
print('%s is over' % name)
if __name__ == '__main__':
t = Thread(target=task,args=(('hp',)))
t.start()
t.join() #主线程等待子线程结束再执行
print('主线程')
同一个进程下的多个线程的数据是共享的
from threading import Thread
import time
money = 100
def task():
global money
money = 666
print(money)
if __name__ == '__main__':
t = Thread(target=task)
t.start()
t.join()
print(money)
线程对象及属性方法
from threading import Thread , active_count , current_thread
import os,time
def task(n):
print('hello world',current_thread().name) # current_thread().name获取当前线程的名字,子线程
time.sleep(n)
if __name__ == '__main__':
t = Thread(target=task,args=(1,))
t1 = Thread(target=task,args=(2,))
t.start()
t1.start()
t.join()
print('主',active_count()) # active_count()统计当前正在活跃的线程数
# print('主',os.getpid()) # 获取当前进程的pid号
# print('主', current_thread().name) # 获取当前主线程名字
守护线程
from threading import Thread
import time
def task(name):
print('%s is running' % name)
time.sleep(1)
print('%s is over' % name)
if __name__ == '__main__':
t = Thread(target=task,args=('hp',))
t.daemon = True
t.start()
print('主线程')
'''
主线程运行结束之后不会立刻结束 会等待所有其他非守护线程结束才会结束
'''
# 例子
from threading import Thread
import time
def foo():
print(123)
time.sleep(1)
print('end123')
def func():
print(456)
time.sleep(3)
print('end456')
if __name__ == '__main__':
t1 = Thread(target=foo)
t2 = Thread(target=func)
t1.daemon = True
t1.start()
t2.start()
print('主....')
线程互斥锁
from threading import Thread, Lock
import time
money = 100
mutex = Lock()
def task():
global money
mutex.acquire()
tmp = money
time.sleep(0.1)
money = tmp - 1
mutex.release()
if __name__ == '__main__':
t_list = []
for i in range(100):
t = Thread(target=task)
t.start()
t_list.append(t)
for t in t_list:
t.join()
print(money)
GIL全局解析器锁
python解析器有很多版本,其中包括:Cpython,Jpython,Pypypython。普遍使用的都是Cpython解析器。
- CIL不是python的特点而是Cpython解析器的特点
- GIL是保证解析器级别的数据安全
- GIL会导致同一个进程下的多个线程的无法同时执行即无法利用多核优势
- 针对不同的数据还是需要加不同的锁处理
在Cpython解析器中GIL是一把互斥锁,用来阻止同一个进程下的多个线程的同时执行。简单来说,就是进程下的多个线程无法利用多核优势。
原因:Cpython中的 内存管理(垃圾回收机制)不是线程安全的
内存管理(垃圾回收机制)
- 应用计数
- 标记清楚
- 分代回收
GIL与普通互斥锁的区别
from threading import Thread, Lock
import time
mutex = Lock()
money = 100
def task():
global money
mutex.acquire()
tmp = money
time.sleep(0.1)
money = tmp - 1
mutex.release()
if __name__ == '__main__':
t_list = []
for i in range(100):
t = Thread(target=task)
t.start()
t_list.append(t)
for t in t_list:
t.join()
print(money)
'''
100个线程起来之后 先抢GIL
进入io GIL自动释放 但是手上还有一把自己的互斥锁
其他线程抢到GIL但是没有抢到互斥锁
最终GIL还是回到你的手上,按你的照步骤操作数据
'''
多进程与多线程比较
同一程序的多线程
'''
多线程是否有用看具体情况:
单核:四个任务(IO密集型\计算密集型)
多核:四个任务(IO密集型\计算密集型)
'''
#计算密集型 每个任务都需要10s
单个:
多进程:额外消耗资源
多线程:节省开销
多核:
多进程:总耗时 10+
多线程:总耗时 40+
# IO密集型
多核:
多进程:相对浪费资源
多线程:更加节省资源
验证
# 计算密集型
from multiprocessing import Process
from threading import Thread
import os, time
def work():
res = 0
for i in range(100000):
res *= i
if __name__ == '__main__':
l = []
print(os.cpu_count()) #获取当前计算机CPU个数
start_time = time.time()
for i in range(8):
p = Process(target=work) # 0.4827229976654053
t = Thread(target=work) # 0.04627394676208496
p.start()
l.append(p)
# t.start()
# l.append(t)
for p in l:
p.join()
print(time.time()-start_time)
# IO密集型
from multiprocessing import Process
from threading import Thread
import os, time
def work():
time.sleep(2)
if __name__ == '__main__':
l = []
print(os.cpu_count()) #获取当前计算机CPU个数
start_time = time.time()
for i in range(400):
p = Process(target=work) # 22.63789129257202
t = Thread(target=work) # 2.0869174003601074
# p.start()
# l.append(p)
t.start()
l.append(t)
for p in l:
p.join()
print(time.time()-start_time)
总结
'''
多进程和多线程都有各自的优势
写项目的时候都是多进程下面再开多线程
这样可以利用多核优势也可以节省资源消耗
'''
进程池与线程池
无论开设进程还是开设线程都需要消耗资源,只不过开设线程的消耗比开设进程的消耗小。
我们不可能做到无限制的开设进程和线程,因为计算机的硬件资源跟不上。硬件的开发速度远远跟不上软件。
因此在保证计算机硬件能够正常工作的情况下最大限度的利用它。
池的概念
池是用来保证计算机硬件安全的情况下做大限度的利用计算机。
它降低了程序的运行效率但是保证计算机硬件的安全,从而让程序能够运行。
基本使用
线程池
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
import time
# 括号内可以传数字,不传的话默认会开设当前计算机cpu个数的5倍的线程
pool = ThreadPoolExecutor(5) # 池子内固定5个线程
'''
池子造出来后,里面会固定存在5个线程
这5个线程不会出现重复创建和销毁的过程
池子的使用:
将需要运行的任务往池子中提交,池子会自动服务
'''
def task(n):
print(n)
time.sleep(2)
'''
任务提交方式:
同步:提交任务之后原地等待任务返回结果 期间不做任何事情
异步:提价任务之后不等待任务返回结果,继续往下执行
任务结果通过异步回调机制
'''
# pool.submit(task, 1) # 往池子中提交任务 异步提交
# print('主')
t_list = []
for i in range(20):
res = pool.submit(task, i) # <Future at 0x1c3fbd4c048 state=running>
# print(res.result()) # result方法
t_list.append(res)
#等待线程池中所有任务执行完毕之后再往下执行
pool.shutdown() #关闭线程池 等待线程池中所有的任务运行完毕
for t in t_list:
print('>>>:',t.result()) # 有序的
'''
程序由并发变成串行
res.result()拿到的是异步提交的返回结果
'''
进程池
# 进程池
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
import time, os
pool = ProcessPoolExecutor()
# 括号内可以传数字,不传的话默认会开设当前计算机cpu个数进程
'''
池子造出来之后,里面固定几个进程
这几个进程不会出现重复创建和销毁的过程
'''
def task(n):
print(n,os.getpid())
time.sleep(2)
return n**n
def call_back(n):
print('call_back:',n.result())
if __name__ == '__main__':
t_list = []
for i in range(20):
# res = pool.submit(task, i) # <Future at 0x1c3fbd4c048 state=running>
res = pool.submit(task, i).add_done_callback(call_back) #异步回调结果
# print(res.result()) # result方法
# t_list.append(res)
# pool.shutdown() #关闭进程池 等待进程程池中所有的任务运行完毕
# # for t in t_list:
# # print('>>>:',t.result()) # 有序的
协程
概念
进程:资源单位
线程:执行单位
协程:程序员自己想出来的,根本不存在
单线程下实现并发效果,程序员在代码层面上检测所有IO操作,一旦遇上IO,在代码级别上完成切换,这样给CPU感觉程序一直在运行,没有IO从而提升程序的运行效率。
代码层面
切换+保存状态
切换
切换不一定是提升效率,也可能降低效率。IO切换提升效率,没有IO切换则降低效率。
保存状态
保存上一次执行的状态,下一次接着上一次的操作继续往下执行
yield
yield关键字
import time
# def func1():
# for i in range(1000000):
# i + 1
#
# def func2():
# for i in range(1000000):
# i + 1
# start_time = time.time()
# func1()
# func2()
# print(time.time()-start_time)
# 切换 + yield 时间长
def func1():
while True:
1000000 + 1
yield
def func2():
g = func1() # 先初始化出生成器
for i in range(1000000):
i + 1
next(g)
start_time = time.time()
func2()
print(time.time() - start_time)
gevent模块
实现同步并发或异步编程,遇到IO阻塞时会自动切换任务。
安装
pip install gevent
使用
from gevent import monkey;monkey.patch_all() # 猴子补丁
from gevent import spawn
import time
'''
gevent模块本身无法检测常见的一些io操作
在使用的时候需要额外的导入一句话
from gevent import monkey # 猴子补丁
monkey.patch_all()
由于上面两句话在使用gevent模块的时候肯定要导入的
所以还支持简写
from gevent import monkey;monkey.patch_all()
'''
def heng():
print('哼')
time.sleep(2)
print('哼')
def ha():
print('哈')
time.sleep(3)
print('哈')
start_time = time.time()
g1 = spawn(heng)
g2 = spawn(ha)
g1.join()
g2.join() # 等待被检测的任务执行完毕 再往后继续执行
print(time.time() - start_time) # 3.0231306552886963
# heng()
# ha()
# print(time.time() - start_time) # 5.000835418701172
asyncio
在python3.4版本后支持使用
import asyncio
@asyncio.coroutine
def func1():
print(1)
# 网络IO请求:下载图片
yield from asyncio.sleep(2) # 遇到ID操作,自动切换到tasks中的其他任务
print(2)
@asyncio.coroutine
def fun2():
print(3)
# 网络IO请求:下载图片
yield from asyncio.sleep(2)
print(4)
tasks = [
asyncio.ensure_future(func1()),
asyncio.ensure_future(func2()),
]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
注意:遇到IO自动切换
async & await关键字
在python3.5版本之后才能使用
import asyncio
async def func1():
print(1)
# 网络IO请求:下载图片
await asyncio.sleep(2) # 遇到ID操作,自动切换到tasks中的其他任务
print(2)
async def fun2():
print(3)
# 网络IO请求:下载图片
await asyncio.sleep(2)
print(4)
tasks = [
asyncio.ensure_future(func1()),
asyncio.ensure_future(func2()),
]
# 生成获取一个循环事件
loop = asyncio.get_event_loop()
# 将任务放到任务列表
loop.run_until_complete(asyncio.wait(tasks))
# asyncio.run(asyncio.wait(tasks)) # python3.7使用该方法创建
Task对象
在事件循环中添加多个任务。
Tasks用于并发调度协程,通过asyncio.create_task(协程对象)
的方式创建Task对象,这样可以让协程加入到事件循环中等待被调度执行。除了使用asyncio.create_task()
函数创建,还可以使用低层级的loop.create_task()
或ensure_future()
函数。不建议手动实例化创建Task对象。
注意:asyncio.create_task()
函数在Python3.7中被加入的。在Python3.7之前,使用asyncio.ensure_future()
函数。
示例1:
import asyncio
async def func():
print(1)
await asyncio.sleep(2)
print(2)
return "返回值"
async def main():
print("main函数开始")
# 创建Task对象,将当前执行的func函数添加到事件循环中
# name给协程对象起名字
task_list = [
asyncio.create_task(func(),name='n1'),
asyncio.create_task(func(),name='n2')
]
print("main结束")
# 当执行某协程遇到IO操作时,会自动切换到其他任务
# done获取的是执行完返回的结果集合,可以通过name获取是哪个协程的结
# timeout等待时间,None,表示全部协程执行完成
done,pending = await asyncio.wait(task_list,timeout=None)
print(done)
asyncio.run(main())
示例2:
import asyncio
async def func():
print(1)
await asyncio.sleep(2)
print(2)
return "返回值"
task_list = [
func(),
func(),
]
done,pending = asyncio.run(asyncio.wait(task_list))
print(done)
Future对象
Task继承Future,Task对象内部await结果的处理基于Future对象来的。
示例:
async def main():
# 获取当前事件循环
loop = asyncio.get_running_loop()
# 创建一个任务(Future对象),这个任务什么都不做
fut = loop.create_future()
# 等待任务最终结构钢(Future对象),没有结果则会一直等下去
await fut
asyncio.run(main())
协程实现TCP服务端并发
from gevent import monkey;monkey.patch_all()
from gevent import spawn
from threading import Thread
import socket
def communication(conn):
while True:
try:
data = conn.recv(1024)
if len(data) == 0:break
conn.send(data.upper())
except Exception as e:
print(e)
break
conn.close()
def server(ip, port):
server = socket.socket()
server.bind((ip, port))
server.listen(5)
while True:
conn, addr = server.accept()
spawn(communication,conn)
if __name__ == '__main__':
g1 = spawn(server,'127.0.0.1',8080)
g1.join()
异步redis
pip install aioredis
示例:
import asyncio
import aioredis
async def execute(address,password):
print("开始执行",address)
# 网络IO操作,创建redis连接
redis = await aioredis.create_redis(address,password=password)
# 网络IO操作:redis中设置哈希值car,内部在设三个键值对,即:redis={car:{key1:1,key2:2,key3:3}}
await redis.hmset_dict('car',encoding='utf-8')
print(result)
redis.close()
# 网络IO操作:关闭redis连接
await redis.wait_closed()
print("结束",address)
asyncio.run(execute('redis:127.0.0.1:6379',"密码"))
异步MySql
pip install aiomysql
示例1:
import asyncio
import aiomysql
async def execute():
# 网络IO操作,创建mysql连接
conn = await aiomysql.connect(host='127.0.0.1',post=3306,user='root',password='123',db='mysql')
# 网络IO操作:创建CURSOR
cur = await conn.cursor()
# 网络IO操作:执行SQL
await cur.execute("SELECT HOST,User FORM user")
# 网络IO操作:获取SQL结果
result = await cur.fetchall()
print(result)
# 网络IO操作:关闭链接
await cur.close()
conn.close()
asyncio.run(execute())
Python 多道技术以及进程、线程和协程的更多相关文章
- python进程.线程和协程的总结
I.进程: II.多线程threading总结 threading用于提供线程相关的操作,线程是应用系统中工作的最小单位(cpu调用的最小单位). Python当前版本的多线程没有实现优先级,线程组, ...
- python自动化开发-[第十天]-线程、协程、socketserver
今日概要 1.线程 2.协程 3.socketserver 4.基于udp的socket(见第八节) 一.线程 1.threading模块 第一种方法:实例化 import threading imp ...
- python基础之进程间通信、进程池、协程
进程间通信 进程彼此之间互相隔离,要实现进程间通信(IPC),multiprocessing模块支持两种形式:队列和管道,这两种方式都是使用消息传递的. 进程队列queue 不同于线程queue,进程 ...
- python系列7进程线程和协程
目录 进程 线程 协程 上下文切换 前言:线程和进程的关系图 由下图可知,在每个应用程序执行的过程中,都会去产生一个主进程和主线程来完成工作,当我们需要并发的执行的时候,就会通过主进程去生成一系列的 ...
- Python(八)进程、线程、协程篇
本章内容: 线程(线程锁.threading.Event.queue 队列.生产者消费者模型.自定义线程池) 进程(数据共享.进程池) 协程 线程 Threading用于提供线程相关的操作.线程是应用 ...
- 11.python之线程,协程,进程,
一,进程与线程 1.什么是线程 线程是操作系统能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行 ...
- Python进阶(5)_进程与线程之协程、I/O模型
三.协程 3.1协程概念 协程:又称微线程,纤程.英文名Coroutine.一句话说明什么是线程:协程是一种用户态的轻量级线程. 协程拥有自己的寄存器上下文和栈.协程调度切换时,将寄存器上下文和栈保存 ...
- Python学习之路--进程,线程,协程
进程.与线程区别 cpu运行原理 python GIL全局解释器锁 线程 语法 join 线程锁之Lock\Rlock\信号量 将线程变为守护进程 Event事件 queue队列 生产者消费者模型 Q ...
- Python—进程、线程、协程
一.线程 线程是操作系统能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务 方法: ...
随机推荐
- 聊一聊Web端的即时通讯
聊一聊Web端的即时通讯 Web端实现即时通讯的方法有哪些? - 短轮询 长轮询 iframe流 Flash Socket 轮询 客户端定时向服务器发送Ajax请求,服务器接到请求后马上返回响应信息并 ...
- ASP.NET WebAPI解决跨域问题
跨域是个很蛋疼的问题...随笔记录一下... 一.安装nuget包:Microsoft.AspNet.WebApi.Core 二.在Application_Start方法中启用跨域 1 protect ...
- 【每日日报】第三十四天---Scanner类的应用
1 今天继续看书 Scanner类的应用 1 package File; 2 import java.util.Scanner; 3 4 public class ScannerDemo { 5 pu ...
- 【Android开发】【数据库】LitePal 数据库的使用
一,导包 dependencies { ...... // LitePal的包 compile 'org.litepal.android:core:1.3.1' ...... } 二,创建bean类 ...
- lunix或者centos服务器下如何下载自己在github上面的项目代码
1.在github找到项目压缩包下载地址 打开自己的github主页找到需要下载的项目首页,如图所示,找到zip下载地址(ps:如何找这个地址我就不多说了,了解过一点html的同学肯定很容易可以找到) ...
- SpringMVC 解析(四)编程式路由
多数情况下,我们在使用Spring的Controller时,会使用@RequestMapping的形式把请求按照URL路由到指定方法上.Spring还提供了一种编程的方式去实现请求和路由方法之间的路由 ...
- caioj 1000: [视频]整数运算[水题]
题目大意:输入两个整数a和b,输出他们的和. 题解:水题不用题解,简单看一下就知道了-- 代码: #include <cstdio> int a, b; int main() { whil ...
- CTF大赛模拟-CFS三层内网漫游
CTF大赛模拟-CFS三层内网漫游 环境: 三台虚拟机,三个网络. target 1:192.168.161.178 ,192.168.52.132 (linux) target 2:192.168. ...
- MySQL 表数据多久刷一次盘?
前言 事情是这样的,在某乎的邀请回答中看到了这个问题: - 然后当时我没多想就啪一下写下来这样的答案: 这个其实要通过 MySQL 后台线程来刷的,在 Buffer Pool 中被修改的过的 Page ...
- RENIX软件V6板卡速率设置——网络测试仪实操
本文主要介绍RENIX软件V6板卡速率设置相关操作.全文分为V6板卡介绍.如何配置端口两大部分.其中从添加和连接机箱.预约端口.配置端口为强制10M.配置端口为自协商100M.配置说明五个方面详细介绍 ...