[Python] RPC实现
单线程同步
- 使用socket传输数据
- 使用json序列化消息体
- struct将消息编码为二进制字节串,进行网络传输
消息协议

1 // 输入
2 {
3 in: "ping",
4 params: "ireader 0"
5 }
6
7 // 输出
8 {
9 out: "pong",
10 result: "ireader 0"
11 }
客户端 client.py

1 # coding: utf-8
2 # client.py
3
4 import json
5 import time
6 import struct
7 import socket
8
9
10 def rpc(sock, in_, params):
11 response = json.dumps({"in": in_, "params": params}) # 请求消息体
12 length_prefix = struct.pack("I", len(response)) # 请求长度前缀
13 sock.sendall(length_prefix)
14 sock.sendall(response)
15 length_prefix = sock.recv(4) # 响应长度前缀
16 length, = struct.unpack("I", length_prefix)
17 body = sock.recv(length) # 响应消息体
18 response = json.loads(body)
19 return response["out"], response["result"] # 返回响应类型和结果
20
21 if __name__ == '__main__':
22 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
23 s.connect(("localhost", 8080))
24 for i in range(10): # 连续发送10个rpc请求
25 out, result = rpc(s, "ping", "ireader %d" % i)
26 print out, result
27 time.sleep(1) # 休眠1s,便于观察
28 s.close() # 关闭连接

服务端 blocking_single.py

1 # coding: utf8
2 # blocking_single.py
3
4 import json
5 import struct
6 import socket
7
8
9 def handle_conn(conn, addr, handlers):
10 print addr, "comes"
11 while True: # 循环读写
12 length_prefix = conn.recv(4) # 请求长度前缀
13 if not length_prefix: # 连接关闭了
14 print addr, "bye"
15 conn.close()
16 break # 退出循环,处理下一个连接
17 length, = struct.unpack("I", length_prefix)
18 body = conn.recv(length) # 请求消息体
19 request = json.loads(body)
20 in_ = request['in']
21 params = request['params']
22 print in_, params
23 handler = handlers[in_] # 查找请求处理器
24 handler(conn, params) # 处理请求
25
26
27 def loop(sock, handlers):
28 while True:
29 conn, addr = sock.accept() # 接收连接
30 handle_conn(conn, addr, handlers) # 处理连接
31
32
33 def ping(conn, params):
34 send_result(conn, "pong", params)
35
36
37 def send_result(conn, out, result):
38 response = json.dumps({"out": out, "result": result}) # 响应消息体
39 length_prefix = struct.pack("I", len(response)) # 响应长度前缀
40 conn.sendall(length_prefix)
41 conn.sendall(response)
42
43
44 if __name__ == '__main__':
45 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 创建一个TCP套接字
46 sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 打开reuse addr选项
47 sock.bind(("localhost", 8080)) # 绑定端口
48 sock.listen(1) # 监听客户端连接
49 handlers = { # 注册请求处理器
50 "ping": ping
51 }
52 loop(sock, handlers) # 进入服务循环

多线程同步
- 使用线程库thread创建原生线程
- 服务器可并行处理多个客户端
服务端 multithread.py


多进程同步
- Python的GIL导致单个进程只能占满一个CPU核心,多线程无法利用多核优势
- os.fork()会生成子进程
- 子进程退出后,父进程需使用waitpid系统调用收割子进程,防止其称为僵尸资源
- 在子进程中关闭服务器套接字后,在父进程中也要关闭服务器套接字
- 因为进程fork后,父子进程都有自己的套接字引用指向内核的同一份套接字对象,套接字引用计数为2,对套接字进程close,即将套接字对象的引用计数减1
服务端 multiprocess.py

PreForking同步
- 进程比线程耗费资源,通过PreForking进程池模型对服务器开辟的进程数量进行限制,避免服务器负载过重
- 如果并行的连接数量超过了prefork进程数量,后来的客户端请求将会阻塞
单进程异步
- 通过事件轮询API,查询相关套接字是否有响应的读写事件,有则携带事件列表返回,没有则阻塞
- 拿到读写事件后,可对事件相关的套接字进行读写操作
- 设置读写缓冲区
- Nginx/Nodejs/Redis都是基于异步模型
- 异步模型编码成本高,易出错,通常在公司业务代码中采用同步模型,仅在讲究高并发高性能的场合才使用异步模型
PreForking异步
- Tornado/Nginx采用了多进程PreForking异步模型,具有良好的高并发处理能力

参考
Python多线程和多进程
https://www.cnblogs.com/yssjun/p/11302500.html
[Python] RPC实现的更多相关文章
- Python RPC 之 gRPC
gRPC 简介: gRPC 是一款高性能.开源的 RPC 框架,产自 Google,基于 ProtoBuf 序列化协议进行开发,支持多种语言(Golang.Python.Java等),本篇只介绍 Py ...
- Python RPC 不会?不妨看看这篇文章
1. 前言 大家好,我是安果! RPC,全程为 Remote Procedure Call,是一种进程间的通信方式,它采用「 服务端 / 客户机 」模式,是一种请求响应模型 其中,服务端负责提供服务程 ...
- python rpc 的实现
所谓RPC,是远程过程调用(Remote Procedure Call)的简写,网上解释很多,简单来说,就是在当前进程调用其他进程的函数时,体验就像是调用本地写的函数一般.本文实现的是在本地调用远端的 ...
- python使用grpc调用rpc接口
proto文件: syntax = "proto3"; package coupon; // //message UnsetUseC2URequest { // int64 bid ...
- python thrift使用实例
前言 Apache Thrift 是 Facebook 实现的一种高效的.支持多种编程语言的远程服务调用的框架.本文将从 Python开发人员角度简单介绍 Apache Thrift 的架构.开发和使 ...
- RPC简介及框架选择
简单介绍RPC协议及常见框架,对比传统restful api和RPC方式的优缺点.常见RPC框架,gRPC及序列化方式Protobuf等 HTTP协议 http协议是基于tcp协议的,tcp协议是流式 ...
- 服务治理与RPC · 跬步
以前写过Django中使用zerorpc的方法,但是由于我们的Django是运行在gevent下,而zeromq需要启动一个后台进程处理消息,与gevent使用的greenlet携程是冲突的. 在Ja ...
- Odoo14 rpc
odoo14中rpc调用分为两种. 一种是外部调用rpc来访问odoo数据,这个时候你需要登录授权. 另一种是我们自己编写的widget小部件或者自定义视图时候通过js通过rpc去获取数据. 这里说的 ...
- [源码解析] PyTorch 分布式 Autograd (3) ---- 上下文相关
[源码解析] PyTorch 分布式 Autograd (3) ---- 上下文相关 0x00 摘要 我们已经知道 dist.autograd 如何发送和接受消息,本文再来看看如何其他支撑部分,就是如 ...
随机推荐
- python3使用cv2对图像进行基本操作
技术背景 在机器视觉等领域,最基本的图像处理处理操作,可以通过opencv这个库来实现.opencv提供了python的接口,所需安装的库为opencv-python,但是在库的导入的时候一般用的是i ...
- 安装mongoDB出现的问题:无法启动
在我的电脑- 管理 - 服务-中会出现一个MongoDB Server的服务,你需要去手动删除这个服务删除指令: 在cmd管理员模式下使用: sc delete MongoDB Server 然后再配 ...
- 【Java并发】1. Java线程内存模型JMM及volatile相关知识
Java招聘知识合集:https://www.cnblogs.com/spzmmd/tag/Java招聘知识合集/ 该系列用于汇集Java招聘需要的知识点 JMM 并发编程的三大特性:可见性(vola ...
- Leedcode算法专题训练(树)
递归 一棵树要么是空树,要么有两个指针,每个指针指向一棵树.树是一种递归结构,很多树的问题可以使用递归来处理. 1. 树的高度 104. Maximum Depth of Binary Tree (E ...
- [Skill]VBA零基础入门及实践:根据链接展示图片
简介 VBA(Visual Basic for Applications)是依附在应用程序(例如Excel)中的VB语言.只要你安装了Office Excel就自动默认安装了VBA,同样Word和Po ...
- SpringBoot-如何设计优秀的后端接口?
1 概述 本篇文章以Spring Boot为基础,从以下三个方向讲述了如何设计一个优秀的后端接口体系: 参数校验:涉及Hibernate Validator的各种注解,快速失败模式,分组,组序列以及自 ...
- 由孙悟空的七十二变看Java设计模式:装饰者模式
目录 应用场景 代码示例 改进代码 装饰者模式 定义 意图 主要解决问题 何时使用 优缺点 孙悟空的七十二变 应用场景 京东.天猫双十一,情人节商品大促销,各种商品有不同的促销活动 满减:满200减5 ...
- JVM调优基础到进阶
GC和GC Tuning GC的基础知识 1.什么是垃圾 C语言申请内存:malloc free C++: new delete c/C++ 手动回收内存 Java: new ? 自动内存回收,编程上 ...
- Azure data studio 跨平台数据库管理工具试用
最近折腾 azure sql database 的时候发现了微软的一款新的数据库管理工具: azure data studio.从名字上看 azure data studio 好像是专门为 azure ...
- Day05_20_Java中类的创建和对象的实例化
类的创建和对象的实例化 类的定义 类属于引用数据类型,java语言中所有的.class都属于引用数据类型 在类体当中,方法体之外定义的变量被称为 成员变量,成员变量没有赋值,系统默认是0: 语法结构: ...