协程本质上是单任务,协程依赖于线程
携程相对于线程来讲占用的资源更少(几乎不占什么资源)
- 通过生成器,来实现协程
import time
def work1():
for i in range(10):
print('work1--{}'.format(i))
time.sleep(0.1)
yield
def work2():
for i in range(10):
print('work2----{}'.format(i))
time.sleep(0.1)
yield
#通过生成器实现多任务
g1 = work1()
g2 = work2()
while True:
try:
next(g1)
next(g2)
except StopIteration:
break
greenlet对yield进行了进一步封装(了解即可)
import time
from greenlet import greenlet
def work1():
for i in range(10):
print('work1--{}'.format(i))
g2.switch()
time.sleep(0.1)
def work2():
for i in range(10):
print('work2----{}'.format(i))
g1.switch()
time.sleep(0.1)
g1 = greenlet(work1)
g2 = greenlet(work2)
g1.switch()
g2.switch()
协程:gevent
协程存在于线程之中,线程默认不会等待协程执行
- spawn:开启协程(第一个参数为协程要执行的任务)
- join:让线程等待协程执行
协程之间切换的条件 - gevent.sleep() 协程耗时等待的情况下才会切换
- gevent.monkey.path_all() gevent程序补丁 不需要用gevent.sleep(),只要耗时就会切换到其他协程里面
并发首先考虑 协程 > 线程 > 进程 进程资源占用太大
import gevent
import time
from gevent import monkey
import requests
monkey.patch_all()
from queue import Queue
q = Queue()
for i in range(1000):
q.put('http://www.baidu.com')
def work():
while q.qsize() > 0:
url = q.get()
requests.get(url)
st = time.time()
g1 = gevent.spawn(work)
g2 = gevent.spawn(work)
g3 = gevent.spawn(work)
g4 = gevent.spawn(work)
g5 = gevent.spawn(work)
g1.join()
g2.join()#耗时19.744673013687134
g3.join()#耗时15.10847282409668
g4.join()
g5.join()#耗时12.241680145263672
# work() #耗时38.67655611038208
et = time.time()
print('耗时{}'.format(et-st))
#io耗时操作比较多协程节约的时间越多
- 10000个请求,使用开启2个进程,进程中开启3线程,线程中开启5个协程来处理
(30个协程)
# -*- coding: utf-8 -*-
import time
from threading import Thread
from multiprocessing import Process,Queue
import gevent
import requests
#requests.get('https://www.apple.com/') 如果是mac用户需要打开此条注释,否则网络请求不会执行。
def process_work(q,pname):
'''
每个进程执行的任务函数,在该进程中开启3个线程
创建三个线程
:param q: 进程间通讯的任务队列
:param pname: 进程的名字
:return:
'''
thread_list = []
for i in range(3):
tname = "{}-th-{}".format(pname,i)
print('创建线程{}'.format(tname))
t= Thread(target=thread_work,args=(q,tname))
thread_list.append(t)
t.start()
for t in thread_list:
t.join()
def thread_work(q,tname):
'''
每个线程的执行任务函数,在该线程中开启5个协程
:return:
'''
g_list = []
for i in range(5):
gname = '{}-g-{}'.format(tname,i)
print('创建协程-----{}'.format(gname))
g = gevent.spawn(green_work,q,gname)
g_list.append(g)
print('---------------------',len(g_list))
for i in g_list:
i.join()
def green_work(q,gname):
count = 0
while not q.empty():
url = q.get(timeout=0.01)
# print(url)
requests.get(url)
gevent.sleep(0.001)
count += 1
print('----------协程{}执行了{}个任务'.format(gname,count))
def count_time(func):
def wrapper(*args,**kwargs):
print('开始执行')
start_time = time.time()
func(*args,**kwargs)
end_time = time.time()
print('执行结束')
print('总耗时:{}'.format(end_time-start_time))
return wrapper
@count_time
def main():
q = Queue()
for i in range(1000):
q.put('https://www.apple.com/')
print('队列为空吗',q.empty())
pro_list = []
for i in range(2):
pname = 'pro-{}'.format(i)
print('创建进程{}'.format(pname))
p = Process(target=process_work,args=(q,pname))
p.start()
pro_list.append(p)
for p in pro_list:
p.join()
if __name__ == '__main__':
main()
网友评论