标签:编程 www filename 上下文 int 获取 homepage 客户端 线程
协程是用户态的线程,并非真正意义上的线程,
协程只有一个线程,看起来并发的效果是因为它利用了寄存器的上下文切换,
多线程和多进程比较消耗cpu资源,当遇到修改数据的时候,还会遇到死锁的问题。
协程是最大的发挥了cpu的单核能力,遇到io阻塞就切换,阻塞完成之后切换回来。
协程的好处:
缺点:
yield生成器实现协程的并发效果:
import time
"""
协程:是用户态的线程
yield单线程下实现并发效果
"""
#生产者
def producer(name):
con1.__next__()
con2.__next__()
count = 0
while count < 5:
time.sleep(1)
print("\033[31;1m[producer %s]\033[0m is making baozi..." % name)
con1.send(count)
con2.send(count)
count += 1
#消费者
def consumer(name):
print("准备开始吃包子...")
while True:
baozi = yield
print("[%s]吃了包子[%s]" % (name, baozi))
if __name__ == ‘__main__‘:
con1 = consumer("轩轩")
con2 = consumer("壮壮")
producer("小白")
greenlet代码示例:
from greenlet import greenlet
def homepage():
print("34")
gr2.switch()
print("12")
gr3.switch()
def bbs():
print("84")
gr3.switch()
print("13")
def login():
print("56")
gr1.switch()
print("--end--")
gr1 = greenlet(homepage)
gr2 = greenlet(bbs)
gr3 = greenlet(login)
执行结果:
34
84
56
12
--end--
gevent模块是greentlet模块的简单化:
import gevent
"""
自动档的协程
自上而下从0开始计数,如果计数不大于sleep数,则跳过后面代码
否则,执行后面代码
"""
def run1():
print("run1->1")
gevent.sleep(2)
print("run1->2")
def run2():
print("run2->1")
gevent.sleep(3)
print("run2->2")
def run3():
print("run3->1")
gevent.sleep(1)
print("run3->2")
def run4():
print("run4->1")
gevent.sleep(0)
print("run4->2")
#由上而下依次执行
gevent.joinall([
gevent.spawn(run1),
gevent.spawn(run2),
gevent.spawn(run3),
gevent.spawn(run4),
])
执行结果:
run1->1
run2->1
run3->1
run4->1
run4->2
run3->2
run1->2
run2->2
利用协程实现并发爬取网页内容:
import gevent, time
from gevent import monkey
monkey.patch_all()
from urllib import request
"""
利用协程,高效爬取网页
gevent模块默认不识别urllib的IO操作,
需要导入monkey给urllib里面的操作打上标记
"""
filename = "result.html"
#爬取网页内容到本地
def get_url_content(url):
print("GET: %s" % url)
res = request.urlopen(url)
html = res.read()
with open(filename, "wb") as f:
f.write(html)
print("%d bytes received from %s" % (len(html), url))
print("----------------------")
url_list = [
"https://www.python.org/",
"https://github.com/",
"https://www.bilibili.com/"
]
#启动时间
serial_start_time = time.time()
#串行的方式获取网页内容
for url in url_list:
get_url_content(url)
#计算花费时间
print("serial cost:", time.time() - serial_start_time)
#启动时间
async_start_time = time.time()
#并行的方式获取网页内容
gevent.joinall([
gevent.spawn(get_url_content, "https://www.python.org/"),
gevent.spawn(get_url_content, "https://github.com"),
gevent.spawn(get_url_content, "https://www.bilibili.com/"),
])
#计算花费时间
print("async cost:", time.time() - async_start_time)
协程实现高并发socket服务器:
服务端:
import gevent
from gevent import monkey
monkey.patch_all()
import socket
"""
协程实现socket的高并发服务器
"""
def handle_data(conn):
try:
while True:
data = conn.recv(1024)
if not data:
conn.shutdown(socket.SHUT_WR)
conn.send(data.upper())
except EXception as ex:
print(ex)
finally:
conn.close()
def my_server(port):
server = socket.socket()
#绑定地址和端口
server.bind(("0.0.0.0", port))
#开始监听
server.listen(500)
while True:
#阻塞等待连接
conn, addr = server.accept()
#来数据了
gevent.spawn(handle_data, conn)
if __name__ == ‘__main__‘:
my_server(6666)
客户端:
import socket
"""
协程实现socket高并发的客户端
"""
client = socket.socket()
client.connect(("localhost", 6666))
while True:
input_data = input(">>:").strip()
if not input_data:
continue
client.send(input_data.encode())
data = client.recv(1024).decode()
print(data)
client.close()
标签:编程 www filename 上下文 int 获取 homepage 客户端 线程
原文地址:https://www.cnblogs.com/ericbai/p/9130188.html