python协程实现一万并发_python进阶:服务端实现并发的八种方式

【本文导读】文中有许多不妥之处,敬请批评指正!python编写的服务端,有八种实现并发的方式,如阻塞(对等)套接字实现并发、非阻塞套接字实现并发、epoll实现并发、多进程实现并发、多线程实现并发、进程池实现并发、线程池实现并发、协程实现并发等。

一、什么是并发?

1、套接字:是python与操作系统两者间的一个接口,通过设置对等的IP与端口,实现数据的发送与接收。套接字有三种:服务端监听套接字、服务端对等套接字、客户端(对等)套接字,其中服务端对等套接字与客户端套接字实现数据的传输。

2、阻塞:套接字传输数据时,会出现accept与recv两种阻塞,服务端在没有新的套接字来之前,不能处理已经建立连接的套接字的请求,此时出现accept阻塞;服务端在没有接受到客户端请求数据之前,不能与其他客户端建立连接,此时出现recv阻塞,客户端也会出现类似recv阻塞。

3、进程与并行:多进程实现并行,遵循轮巡调度机制,由多个cpu同时运行,有效解决阻塞问题。并行属于并发。

4、线程与并发:多线程实现并发,遵循轮巡调度机制,一个cpu在一定时间内的并行,由python解释器调度。

二、实现并发的八种方式

(一)阻塞(对等)套接字实现并发的服务端

1、阻塞(对等)套接字实现并发的服务端

# 阻塞(对等)套接字实现并发的服务端

import socket # 导入模块socket(API接口)

server = socket.socket() # 创建服务端

server.bind(('0.0.0.0',8881)) # 绑定ip与端口

server.listen(5) # 开始监听

while True:

conn, address = server.accept() # 获取服务端对等套接字

while True: # 向客户端接收发送数据

client_data = conn.recv(1000)

if client_data:

print("客户端发来的数据",client_data.decode())

conn.send(client_data)

else:

con.close() # 关闭服务端

break

(二)非阻塞套接字实现并发的服务端

1、非阻塞套接字实现并发的服务端:

# 非阻塞套接字实现并发的服务端

import socket # 导入模块socket

server = socket.socket() # 创建服务端

server.setblocking(False) # 套接字设成非阻塞

server.bind(('0.0.0.0',8882)) # 绑定ip与端口

server.listen(5) # 开始监听

conn_list = [] # 套接字列表

while True:

try:

conn,address = server.accept() # 获取服务端对等套接字

conn.setblocking(False) # 套接字设置成非阻塞

conn_list.append(conn) # 套接字放入列表

except BlockingIOError as error: # 捕获异常

pass

for i in conn_list:

try: # 向客户端接收发送数据

recv_data = conn.recv(1024)

if recv_data:

print("客户端发来的数据",recv_data.decode())

conn.send(recv_data)

else:

conn.close() # 关闭服务端

conn_list.remove(conn) # 移除套接字

except BlockingIOError as error: #捕获异常

pass

(三)epoll实现并发的服务端

1、通过epoll实现并发的服务端

# 通过epoll(io多路复用)实现并发的服务端

import socket # 导入模块

import selectors # 导入模块

epoll_selector = selectors.EpollSelector() # 实例化epoll(liunx)

server = socket.socket() # 创建服务端

server.bind(('0.0.0.0',8888)) # 绑定ip与端口

server.listen(1000) # 开始监听

def recv(conn): # 向客户端接收或发送数据

recv_data = conn.recv(1024)

if recv_data:

print("客户端发来的数据",recv_data.decode())

conn.send(recv_data)

else:

epoll_selector.unregister(conn) # 取消事件

conn.close() # 关闭对等套接字

def accept(server):

conn,addr = server.accept() # 获取服务端对等套接字

# 回调函数处理第二个recv阻塞,注册事件:操作系统监控已获取conn、数据等

epoll_selector.register(conn,selectors.EVENT_READ,recv)

# 回调函数处理第一个accept阻塞,注册事件:操作系统监控已获取server、数据等

epoll_selector.register(server,selectors.EVENT_READ,accept)

while True: # 事件循环

events = epoll_selector.select() # 查询准备好的事件,返回列表

# 用print(events)查询事件内容

for key ,mask in events: # 拆包,获取socket、

callback = key.data # 获取accept

sock = key.fileobj # 获取准备好的客户端套接字

callback(sock) # 调用accept函数

(四)多进程实现并发的服务端

1、多进程实现并发的服务端

# 多进程实现并发的服务端

import socket # 导入模块

from multiprocessing import Process # 导入多进程模块

server = socket.socket() # 创建服务端

server.bind(('0.0.0.0',9091)) # 绑定ip与端口

server.listen(1000) # 开始监听

def fun(conn): # 向客户端接收或发送数据

while True:

recv_data = conn.recv(1024)

if recv_data:

print("客户端发来的数据",recv_data.decode())

conn.send(recv_data)

else:

conn.close()

break

while True: # 主进程

conn,addr = server.accept() # 获取服务端对等套接字

p = Process(target=fun,args=(conn,)) # 实例化子进程(连接客户端)

p.start() # 开启子进程

(五)多线程实现并发的服务端

1、多线程实现并发的服务端:

# 多线程实现并发的客户端

import socket # 导入模块

import threading # 导入多线程模块

server = socket.socket() # 创建服务端

server.bind(('0.0.0.0',6668)) # 绑定ip与端口

server.listen(1000) # 开始监听

def fun(conn): # 向客户端接收或发送数据

while True:

recv_data = conn.recv(1024)

if recv_data:

print("客户端发来的数据",recv_data.decode())

conn.send(recv_data)

else:

conn.close()

while True: # 主线程

conn,address = server.accept() # 获取服务端对等套接字

t = threading.Thread(target=fun,args=(conn,)) # 实例化子线程(连接客户端)

(六)使用进程池(进程池)实现并发的服务端

1、使用进程池(进程池)实现并发的服务端

# 使用进程池(进程池)实现并发的服务端

import socket # 导入模块

from multiprocessing import Pool,cpu_count # 导入进程池

from multiprocessing.pool import ThreadPool # 导入线程池

server = socket.socket() # 创建服务端

server.bind(('0.0.0.0',5678)) # 绑定ip与端口

server.listen(1000) # 开始监听

def work_thread(conn): # 向客户端接收或发送数据

while True:

recv_data = conn.recv(1000)

if recv_data:

print("客户端发来的数据",recv_data.decode())

conn.send(recv_data)

else:

conn.close()

break

def work_process(server):

t_pool = ThreadPool(2*cpu_count()) # 准备线程

while True:

conn,address = server.accept() # 获取服务端对等连接套接字

t_pool.apply_async(work_thread,args=(conn,))# 进程池(客户端收发数据)

n = cpu_count() # CPU的核数

p = Pool(n) # 实例化进程池

for i in range(n):

p.apply_async(work_process,args=(server,)) #进程池(accept阻塞)

p.close()

p.join()

(七)使用进程池(多线程)实现并发的服务端

1、使用进程池(多线程)实现并发的服务端

# 使用进程池(多线程)实现并发的服务端

import socket # 导入模块

from multiprocessing import Pool,cpu_count

from threading import Thread # 导入多线程

server = socket.socket() # 创建服务端

server.bind(('0.0.0.0',7777)) # 绑定ip与端口

server.listen(1000) # 开始监听

def work_thread(conn): # 向客户端接收发送数据

while True:

recv_data = conn.recv(1000)

if recv_data:

print("客户端发来的数据",recv_data.decode())

conn.send(recv_data)

else:

conn.close()

break

def work_process(server):

while True:

conn,addr = server.accept() # 获取服务端对等套接字

t = Thread(target=work_thread,args=(conn,)) # 多线程

t.start()

n = cpu_count()

p = Pool(n)

for i in range(n):

p.apply_async(work_process,args=(server,)) # 进程池(accept阻塞)

p.close()

p.join()

(八)协程实现并发的服务端

1、使用协程实现并发的服务端

# 使用协程实现并发的服务端

from gevent import monkey;monkey.patch_socket() # 替换python自带的socket

import gevent # 导入协程

import socket # 导入模块

server = socket.socket() # 创建服务端

server.bind(('0.0.0.0',8989)) # 绑定ip与端口

server.listen(1000) # 开始监听

def worker(conn): # 向客户端接收发送数据

while True:

recv_data = conn.recv(1000)

if recv_data:

print("客户端发来的数据",recv_data.decode())

conn.send(recv_data)

else:

conn.close()

break

while True:

conn,address = server.accept() # 获取服务端对等套接字

gevent.spawn(worker,conn) # 实例化协程,并将conn作为参数传入

三、实现并发的具体操作:

1、先启动服务端(以协程并发为例),端口自己设置。

2、再启动两个客户端,输入数据,与服务端实现数据传输。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值