并发编程——进程池线程池、协程、IO模型

1、socket 服务端实现高并发 网络编程服务端需要满足的要求:

①固定的IP和port

②24H提供服务

③能实现并发

# socket实现并发
# seerver
import socket
from threading import Thread
server = socket.socket()
server.bind(('127.0.0.1',8080))
server.listen(5)


def communicate():
    # 通讯循环
	while True:
		try:
			# 接收数据
			data = conn.recv(1024)
            if len(data) == 0:break
            print(data)
            conn.send(data.upper())
		except ConnectionResetError:
            break
    conn.close()

#连接循环
while TRUE:
    conn addr = server.accept()
	# 开启线程
	t = Thread(target = communicate,args=(conn,))
	t.start()
server
# cliet 
import socket

client = socket.socket()
client.connect(('127.0.0.1',8080))

# 通讯循环
while True:
	info = input('>>>').encode('utf-8')
	if len(info) == 0:continue
    client.send(info)
	data = client.recv(1024)
    print(data)
    conn.close()

#连接循环
while TRUE:
    conn addr = server.accept()
	# 开启线程
	t = Thread(target = communicate,args=(conn,))
	t.start()
client

2、进程池和线程池

进程池和线程池介绍

进程池和线程池都是为了减轻硬件负担,保证程序的运行,相对减少的运行速度

1 模块导入:
	from concurrent.futuers import ThreadPoolExecutor,ProcessPoolExecutor
2 实例化:
#在不知道参数的情况下,默认为当前计算机的cpu个数*5
	线程池:pool = ThreadpoolExecutor(N)
    进程池:pool = ProcesspoolExecutor(N)
3 提交任务
	pool.submit()
  提交任务的两种方式:
	① 同步:提交任务后,原地等待任务的返回结果,再执行下一步代码
	② 异步:提交任务后,不等待任务返回结果(通过回调函数拿到返回值),直接进下一步代码
4 回调函数:add_done_call()
	异步提交后一旦任务有返回结果自定交给另外一个去执行
5 pool.shutdown:
    关闭池子,并且等待池子中所有的任务运行完毕

例子

from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
import time
import os


pool = ProcessPoolExecutor(5)
# pool = ThreadPoolExecutor(5)

def task(n):
    print(n,os.getpid())
    time.sleep(2)
    return n**2

def call_back(n):
    print('拿到结果:%s'%n.result())

if __name__ == '__main__':
    t_list = []
    for i in range(20):
        # 回调函数,异步提交任务
        future = pool.submit(task,i).add_done_callback(call_back)
        t_list.append(future)
        pool.shutdown()
        for p in t_list:
            print(">>>",p.result())
    print('主')


进程池和线程池使用

3、协程

     1、进程:资源单位

     2、线程:执行单位

     3、协程:单线程下实现并

     4、协程是技术人员虚拟出来的的概念,对于操作系统并不存在

核心:切换+保存状态 作用就是将单线程的效率提升到最高,多进程下开多线程,多线程下用协程,实现高并发

优点:协程切换开销小,单线程内实现并发的效果,最大限度的利用cpu

缺点:无法利用多核,一旦阻塞整个线程就会阻塞

怎么使用

1 导入gevent模块
g1=gevent.spawn(func,1,,2,3,x=4,y=5)创建一个协程对象g1,spawn括号内第一个参数是函数名,如eat,后面可以有多个参数,可以是位置实参或关键字实参,都是传给函数eat的
2 g1.join() #等待g1结束
3 g1.value#拿到func1的返回值

协程实现高并发:

from gevent import monkey;monkey.patch_all()
import socket
from gevent import spawn

def communicate(conn):
    while True:
        try:
            data = conn.recv(1024)
            if len(data)==0:break
            print(data.decode('utf-8'))
            conn.send(data.upper())

        except ConnectionResetError:
            break
    conn.close()

def server():
    server = socket.socket()
    server.bind(('127.0.0.1',8080))
    server.listen(5)
    while True:
        conn,addr = server.accept()
        spawn(communicate,conn)

if __name__ == '__main__':
    s1 = spawn(server)
    s1.join()

server
import socket
from threading import Thread,current_thread

def client():
    client = socket.socket()
    client.connect(('127.0.0.1',8080))
    n = 1
    while True:
        data = '%s %s'%(current_thread().name,n)
        n+=1
        client.send(data.encode('utf-8'))
        info = client.recv(1024)
        print(info)

if __name__ == '__main__':
    for i in range(500):
        t = Thread(target=client)
        t.start()


    while True:
        conn,addr = server.accept()
        spawn(communicate,conn)

if __name__ == '__main__':
    s1 = spawn(server)
    s1.join()
client

4 IO 模型

① 阻塞IO

② 非阻塞IO:非阻塞IO(服务端通信针对accept用s.setblocking(False)加异常捕获,cpu占用率过高)

③ IO多路复用:

在只检测一个套接字的情况下,他的效率连阻塞IO都比不上。因为select这个中间人增加了环节。

但是在检测多个套接字的情况下,就能省去wait for data过程

④ 异步IO

原文地址:https://www.cnblogs.com/king-home/p/10839601.html