单线程同步

  • 使用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实现的更多相关文章

  1. Python RPC 之 gRPC

    gRPC 简介: gRPC 是一款高性能.开源的 RPC 框架,产自 Google,基于 ProtoBuf 序列化协议进行开发,支持多种语言(Golang.Python.Java等),本篇只介绍 Py ...

  2. Python RPC 不会?不妨看看这篇文章

    1. 前言 大家好,我是安果! RPC,全程为 Remote Procedure Call,是一种进程间的通信方式,它采用「 服务端 / 客户机 」模式,是一种请求响应模型 其中,服务端负责提供服务程 ...

  3. python rpc 的实现

    所谓RPC,是远程过程调用(Remote Procedure Call)的简写,网上解释很多,简单来说,就是在当前进程调用其他进程的函数时,体验就像是调用本地写的函数一般.本文实现的是在本地调用远端的 ...

  4. python使用grpc调用rpc接口

    proto文件: syntax = "proto3"; package coupon; // //message UnsetUseC2URequest { // int64 bid ...

  5. python thrift使用实例

    前言 Apache Thrift 是 Facebook 实现的一种高效的.支持多种编程语言的远程服务调用的框架.本文将从 Python开发人员角度简单介绍 Apache Thrift 的架构.开发和使 ...

  6. RPC简介及框架选择

    简单介绍RPC协议及常见框架,对比传统restful api和RPC方式的优缺点.常见RPC框架,gRPC及序列化方式Protobuf等 HTTP协议 http协议是基于tcp协议的,tcp协议是流式 ...

  7. 服务治理与RPC · 跬步

    以前写过Django中使用zerorpc的方法,但是由于我们的Django是运行在gevent下,而zeromq需要启动一个后台进程处理消息,与gevent使用的greenlet携程是冲突的. 在Ja ...

  8. Odoo14 rpc

    odoo14中rpc调用分为两种. 一种是外部调用rpc来访问odoo数据,这个时候你需要登录授权. 另一种是我们自己编写的widget小部件或者自定义视图时候通过js通过rpc去获取数据. 这里说的 ...

  9. [源码解析] PyTorch 分布式 Autograd (3) ---- 上下文相关

    [源码解析] PyTorch 分布式 Autograd (3) ---- 上下文相关 0x00 摘要 我们已经知道 dist.autograd 如何发送和接受消息,本文再来看看如何其他支撑部分,就是如 ...

随机推荐

  1. 为什么数据库字段要使用NOT NULL?

    最近刚入职新公司,发现数据库设计有点小问题,数据库字段很多没有NOT NULL,对于强迫症晚期患者来说,简直难以忍受,因此有了这篇文章. 基于目前大部分的开发现状来说,我们都会把字段全部设置成NOT ...

  2. redis setNx原子锁

    https://github.com/suqi/rlock/blob/master/rlock.py 保持逻辑并发情况不产生多次结果 常用于下单,钱包,抢购,秒杀等场景 1 LOCK_TIMEOUT ...

  3. [深搜]C. 【例题3】虫食算

    C . [ 例 题 3 ] 虫 食 算 题目解析 正解 : Dfs + 剪枝 依题意,把样例以加法的形式展现出来. 根据加法的性质,可以得出有两种情况:有进位和没有进位的. 而从百位到最高位的结果,又 ...

  4. java面试-什么是GC root

    一.什么是垃圾 内存中已经不再被使用到的空间就是垃圾 二.要进行垃圾回收,如何判断一个对象是否可以被回收? 引用计数法 很难解决对象之间的循环引用问题 枚举根节点做可达性分析 通过一系列名为" ...

  5. 【接入指南】一个Demo带你玩转华为帐号服务

    在<接入指南:一文带你了解华为帐号服务>中已经给大家介绍了华为帐号服务有哪些优势,如一键授权登录华为全场景共享.共享华为帐号所有用户资源.帐号安全可靠.接入方便快捷等,以及为什么能帮助开发 ...

  6. Salesforce学习之路(三)利用VS Code结合Git开发Salesforce

    在前面说了一些有关Admin的知识,但实际开发运用中,仅凭Admin的配置很难满足项目的定制化需求,因此基于CRM的二次开发则应运而生. 由于国内资料相对较少,所以很多入门新手无处下手,那这里就简单介 ...

  7. w1R3s靶机work_through

    前言 这靶机挺简单的.虽然网友们有分享oscp向的靶机集,但是没有一个难度梯度,做起来就怪怪的. 打点 nmap -sP 192.168.218.0/24 发现主机IP 192.168.218.134 ...

  8. 2021S软件工程——个人阅读作业1

    2021S软件工程--个人阅读作业1 项目 内容 这个作业属于哪个课程 2021春季软件工程(罗杰 任建) 这个作业的要求在哪里 2021年软工-热身阅读作业 我在这个课程的目标是 了解并熟悉软件开发 ...

  9. SpringCloud-微服务架构编码构建

    SpringCloud Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智能路由,微代理,控制总线).分布式系统的协调导致了样板模式, ...

  10. ASP去除所有html标签

    ASP去除所有html标签 function nohtml(str) dim re Set re=new RegExp re.IgnoreCase =true re.Global=True re.Pa ...