协程(效率最快、重点)--初识协程、gevent模块、协程爬虫、协程socket(一)

https://www.cnblogs.com/post/readauth?url=/mys6/p/10803772.html
初识协程
# 进程 启动多个进程 进程之间是由操作系统负责调用(时间片切换,人眼看似同时运行)
# 线程 启动多个线程 真正被CPU执行的最小单位实际是线程(也可形成看似同时运行并发效果,由于python语言中CPython无法多线程使用多CPU,
但其他语言多线程可使用多CPU,所以PYTHON不适合计算类程序,因为计算需要用到CPU)
# 开启一个线程 创建一个线程(一小块内存消耗》》寄存器 堆栈)
# 关闭一个线程(也需小量内存开销)
# 协程
# 本质上是一个线程
# 能够在多个任务之间(程序之间)切换来节省一些IO时间
# 协程中任务之间的切换也消耗时间,但是开销要远远小于进程线程之间的切换
# 实现并发的手段


# 一个简单模拟协程概念(两个函数之间切换)
# import time
# def consumer():
# while True:
# x = yield(生成器)
# time.sleep(1)
# print('处理了数据 :',x)
#
# def producer():
# c = consumer()
# next(c)
# for i in range(10):
# time.sleep(1)
# print('生产了数据 :',i)
# c.send(i)
#
# producer()

 




# 真正的协程模块就是使用greenlet完成的切换
# from greenlet import greenlet
# def eat():
# print('eating start')
# g2.switch()
# print('eating end')
# g2.switch()
#
# def play():
# print('playing start')
# g1.switch()
# print('playing end')
# g1 = greenlet(eat)
# g2 = greenlet(play)
# g1.switch()

 

 nginx负载均衡内部就用到协程(最大并发5W)

 


协程和gevent模块

 

协程规避IO的例子(充分利用IO操作等待时间),无需关系两个函数之间是怎么切换的

gevent模块相当与操作系统对进程的之间的切换一样,gevent是起到对协程遇到IO操作切换

 

 

 

进程是操作系统资源分配单位,线程是CPU最小的执行单位,那协程呢?(就是对线程之间切换操作)

 

 


# from gevent import monkey;monkey.patch_all() #这里如果不导入这段,gevent是无法识别time.sleep(1)(可以识别gevent.sleep(1),但系统时间一般用time模板)
# import time
# import gevent
# import threading
# def eat():
# print(threading.current_thread().getName()) 查看虚拟线程名》》协程名,两个协程
# print(threading.current_thread()) 协程(虚拟线程)ID,不是线程ID号,虽然两个协程ID不一样,但他们是在同一线程里

# print('eating start')
# time.sleep(1)
# print('eating end')
#
# def play():
# print(threading.current_thread().getName())
# print(threading.current_thread())
# print('playing start')
# time.sleep(1)
# print('playing end')
#
# g1 = gevent.spawn(eat) # 开启一个协程
# g2 = gevent.spawn(play)
# g1.join()识别一个程序的结束
# g2.join()

# 进程和线程的任务切换右操作系统完成,不管进程或线程里代码写的什么,到了时间片轮换就切换,
# 协程任务之间的切换由程序(代码)完成,只有遇到协程模块能识别的IO操作的时候,程序才会进行任务切换,实现并发的效果
如果没遇到IO操作,就不会进行任务切换,不能实现并发的效果,而是按代码顺序执行








 


# 同步 和 异步
# from gevent import monkey;monkey.patch_all()
# import time
# import gevent
#
# def task(n):
# time.sleep(1)
# print(n)
#
# def sync(): # 同步方式
# for i in range(10):
# task(i)
#
# def async(): #异步方式,高网络IO情况使用这种协程方式比较好,小IO或计算类不适合用协程
# g_lst = []
# for i in range(10):
# g = gevent.spawn(task,i)
# g_lst.append(g)
# gevent.joinall(g_lst) 传入一个可迭代对象 # 等同于for g in g_lst:g.join()的效果

# sync()
# async()


# 协程 : 能够在一个线程中实现并发效果的概念
# 能够规避一些任务中的IO操作
# 在任务的执行过程中,检测到IO就切换到其他任务

# 多线程 被弱化了
# 协程 在一个线程上 提高CPU 的利用率
# 协程相比于多线程的优势 切换的效率更快

# 爬虫的例子(需要正则基础)
# 请求过程中的IO等待


# from gevent import monkey;monkey.patch_all() 捕获IO或网络延迟
# import gevent
# from urllib.request import urlopen # 内置的模块
# def get_url(url):
# response = urlopen(url)
# content = response.read().decode('utf-8')
# return len(content)
#
# g1 = gevent.spawn(get_url,'http://www.baidu.com')
# g2 = gevent.spawn(get_url,'http://www.sogou.com')
# g3 = gevent.spawn(get_url,'http://www.taobao.com')
# g4 = gevent.spawn(get_url,'http://www.hao123.com')
# g5 = gevent.spawn(get_url,'http://www.cnblogs.com')
# gevent.joinall([g1,g2,g3,g4,g5]) 识别所有代码结束
# print(g1.value)
# print(g2.value)一起打印(并发效果)
# print(g3.value)
# print(g4.value)
# print(g5.value)
# ret = get_url('http://www.baidu.com')
# print(ret)
协程socket

server端
from gevent import monkey;monkey.patch_all()
import socket
import gevent
def talk(conn):
conn.send(b'hello')
print(conn.recv(1024).decode('utf-8'))
conn.close()

sk = socket.socket() sk.bind(('127.0.0.1',8080))
sk.listen()
while True: #异步
conn,addr = sk.accept()
gevent.spawn(talk,conn)
sk.close()


client端
import socket
sk = socket.socket()
sk.connect(('127.0.0.1',8080))
print(sk.recv(1024))
msg = input('>>>').encode('utf-8')
sk.send(msg)
sk.close()












 

posted @ 2019-05-19 18:01 大圣的python之路 阅读(...) 评论(...) 编辑 收藏