協程
1.本質是一個線程
2.可以在多個任務之間切換節省io時間
3.協程中任務之間的切換也要消耗時間,可是開銷遠遠小於進程線程之間的切換
4.在任務的執行過程當中,檢測到IO就切換至他任務
5.爬蟲和socket相關的操做,可以使用協程
IO模型
1.阻塞IO
2.非阻塞IO
3.多路複用IO
1.select 機制 (window,linux) 操做系統循環列表中每個被監聽的項,看是否有讀操做
2.poll 機制 (linux) 能夠監聽對象比select多
select 和 poll 機制 都會隨着監聽項的增多,效率下降
3.epoll 機制 linux 更高級的算法,不是循環監聽
1.消費者模型 函數間切換linux
def consumer(): while True: x = yield print('消費了%s數據'%x) def producer(): c = consumer() next(c) for i in range(10): print('製造了%s數據'%i) c.send(i) producer()
2.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()
3.gevent 異步app
from gevent import monkey;monkey.patch_all() import time import gevent def task(): print('******') time.sleep(1) def sync(): for i in range(5): print('sync:') task() def async(): c_list = [] for i in range(5): print('async:') c = gevent.spawn(task) c_list.append(c) gevent.joinall(c_list) sync() async()
4.gevent 爬蟲異步
from gevent import monkey; monkey.patch_all() from urllib.request import urlopen import gevent def func(url): ret = urlopen(url) ret = ret.read().decode('utf-8') return ret url = 'http://www.baidu.com' url1 = 'http://www.taobao.com' url2 = 'http://www.qq.com' url3 = 'http://www.hao123.com' g = gevent.spawn(func,url) g1 = gevent.spawn(func,url1) g2 = gevent.spawn(func,url2) g3 = gevent.spawn(func,url3) gevent.joinall([g,g1,g2,g3]) print(g.value,g1.value,g2.value,g3.value)
5.gevent 實現socketserver socket
# server import socket from gevent import monkey;monkey.patch_all() import gevent def func(conn): conn.send(b'hello') ret = conn.recv(1024).decode('utf-8') print(ret) sk = socket.socket() sk.bind(('127.0.0.1',8080)) sk.listen() while 1 : conn, addr = sk.accept() gevent.spawn(func,conn) conn.close() sk.close() #client import socket sk = socket.socket() sk.connect(('127.0.0.1',8080)) ret = sk.recv(1024).decode('utf-8') print(ret) info = input('>>> ') sk.send(info.encode('utf-8')) sk.close()
6.阻塞IO實現socketserver async
#server import socket sk = socket.socket() sk.bind(('127.0.0.1',8080)) sk.setblocking(False) sk.listen() conn_list = [] del_conn = [] while True: try: conn, addr = sk.accept() print('一個鏈接被創建') conn_list.append(conn) except BlockingIOError: for conn in conn_list: try: msg = conn.recv(1024) if msg == b'': del_conn.append(conn) continue print(msg) conn.send(b'bye bye') except BlockingIOError: pass for conn in del_conn: conn.close() conn_list.remove(conn) del_conn.clear() #client import socket,time import threading def func(): sk = socket.socket() sk.connect(('127.0.0.1',8080)) sk.send(b'hello') time.sleep(1) print(sk.recv(1024)) sk.close() for i in range(2): threading.Thread(target=func).start()
7. 多路複用 IO實現socketserver 函數
#server import select import socket sk = socket.socket() sk.bind(('127.0.0.1',8080)) sk.setblocking(False) sk.listen() read_list = [sk] while 1: r_list, w_list, x_list = select.select(read_list,[],[]) for i in r_list: if i is sk: conn, addr = i.accept() read_list.append(conn) else: ret = i.recv(1024) if ret == b'': i.close() read_list.remove(i) continue print(ret) i.send(b'go') #client import socket,time import threading def func(): sk = socket.socket() sk.connect(('127.0.0.1',8080)) sk.send(b'hello') time.sleep(4) print(sk.recv(1024)) sk.close() for i in range(20): threading.Thread(target=func).start()