标签:编程 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