多线程Python服务器
很多同学在进行编程学习时缺乏系统学习的资料。本页面基于多线程Python服务器内容,从基础理论到综合实战,通过实用的知识类文章,标准的编程教程,丰富的视频课程,为您在多线程Python服务器相关知识领域提供全面立体的资料补充。同时还包含 damain、dart、dataset 的知识内容,欢迎查阅!
多线程Python服务器相关知识
-
并发服务器(二):线程这是并发网络服务器系列的第二节。第一节 提出了服务端实现的协议,还有简单的顺序服务器的代码,是这整个系列的基础。这一节里,我们来看看怎么用多线程来实现并发,用 C 实现一个最简单的多线程服务器,和用 Python 实现的线程池。该系列的所有文章:第一节 - 简介第二节 - 线程第三节 - 事件驱动多线程的方法设计并发服务器说起第一节里的顺序服务器的性能,最显而易见的,是在服务器处理客户端连接时,计算机的很多资源都被浪费掉了。尽管假定客户端快速发送完消息,不做任何等待,仍然需要考虑网络通信的开销;网络要比现在的 CPU 慢上百万倍还不止,因此 CPU 运行服务器时会等待接收套接字的流量,而大量的时间都花在完全不必要的等待中。这里是一份示意图,表明顺序时客户端的运行过程:顺序客户端处理流程这个图片上有 3 个客户端程序。棱形表示客户端的“到达时间”(即客户端尝试连接服务器的时间)。黑色线条表示“等待时间”(客户端等待服务器真正接受连接所用的时间),有色矩形表示“处理时间”(服务器和客户端使用协议进行交互所用的时
-
并发服务器(二):线程这是并发网络服务器系列的第二节。第一节 提出了服务端实现的协议,还有简单的顺序服务器的代码,是这整个系列的基础。这一节里,我们来看看怎么用多线程来实现并发,用 C 实现一个最简单的多线程服务器,和用 Python 实现的线程池。该系列的所有文章:第一节 - 简介第二节 - 线程第三节 - 事件驱动多线程的方法设计并发服务器说起第一节里的顺序服务器的性能,最显而易见的,是在服务器处理客户端连接时,计算机的很多资源都被浪费掉了。尽管假定客户端快速发送完消息,不做任何等待,仍然需要考虑网络通信的开销;网络要比现在的 CPU 慢上百万倍还不止,因此 CPU 运行服务器时会等待接收套接字的流量,而大量的时间都花在完全不必要的等待中。这里是一份示意图,表明顺序时客户端的运行过程:这个图片上有 3 个客户端程序。棱形表示客户端的“到达时间”(即客户端尝试连接服务器的时间)。黑色线条表示“等待时间”(客户端等待服务器真正接受连接所用的时间),有色矩形表示“处理时间”(服务器和客户端使用协议进行交互所用的时间)。有色矩形的末
-
Python多线程----线程池Python多线程----线程池 需求:假设我们现在有一个多线程项目,每有一个用户连接进来,我们的服务器就会创建一个线程。而我们的服务器最多能够承载100个线程,再多就会崩溃。为了防止恶意用户伪装真实用户构建大量的访问来让我们的服务器崩溃,现在需要对线程数量进行限制,一共只有100个线程,并且当一个用户访问结束以后线程会自动归还,等待下一个用户访问。如果100个线程全部被占用则101个用户进入阻塞时间,直到某一个用户退出,线程得到释放,101个用户才能被通行。 不难看出上面的需求
-
一台 Java 服务器可以跑多少个线程?一台Java服务器能跑多少个线程?这个问题来自一次线上报警如下图,超过了我们的配置阈值。 打出jstack文件,通过IBM Thread and Monitor Dump Analyzer for Java工具查看如下: 共计1661个线程,和监控数据得出的吻合。但这个数量应该是大了,我们都知道线程多了,就会有线程切换,带来性能开销。 当时就想到一台java服务器到底可以跑多少个线程呢?跟什么有关系?现整理如下。 每个线程都有一个线程栈空间通过-Xss设置,查了一下我们服务器的关于jvm内存的配置 -Xms4096m -Xmx4096
多线程Python服务器相关课程
多线程Python服务器相关教程
- 浏览器的多线程和单线程 学习过 JavaScript 的可能会了解,JavaScript 的宿主浏览器只有一个线程运行 JavaScript,除了 JavaScript 的线程,浏览器中单个页面还有一些其他线程,例如:UI 线程负责处理渲染 DOM 元素;GUI 线程用于处理与用户交互的逻辑;网络线程用于发送接收 HTTP 请求;file 线程用于读取文件;定时器线程处理定时任务等等。
- 2.4 服务器端解析请求 当一个 HTTP 请求打进服务器之后,一般的流程是:网关层(例如Ngnix)最先获取请求,然后路由转发到具体的Web服务,经过一段业务逻辑之后,可能还会查询数据库,最后将处理的结果返回给浏览器客户端。对于后端开发程序员来说,日常的工作就集中在服务器端,特别是流程图中的"Web业务服务"这块,例如基于 Spring 框架、Django 框架或者ThinkPHP 框架进行业务逻辑开发和上线。(HTTP 请求进入服务器端后的解析流程图)
- 3.1 线程池隔离实现服务资源隔离 通过对处理项目中的工作线程的隔离,来避免工作线程处理接口时所产生的阻塞行为,从而保证工作线程可以顺利地调用接口来满足业务需要。而隔离工作线程的方式,就是为每个接口分配一个线程池,并在线程池中维护一定数量的线程,这样,当上述的接口 2 发生服务资源等待时,由于每个接口都分配了不同的线程池,所以不会影响到后续的 3 4 5 接口,如下图所示:线程池隔离实现原理可以看到,由于为每个服务接口均分配了不同的线程池,所以在接口 2 出现服务等待时,并不会影响后续接口的调用,从而保证了业务的顺利进行。我们继续以 hello 方法为例,来看如何实现线程池隔离。@RequestMapping(value = "hello", method = RequestMethod.GET)@HystrixCommand(threadPoolKey = "HelloHystrix", threadPoolProperties = { @HystrixProperty(name = "coresize", value = "2"), @HystrixProperty(name = "allowMaximumSizeToDivergeFromCoreSize", value = "true"), @HystrixProperty(name = "maximumSize", value = "2"), @HystrixProperty(name = "maxQueueSize", value = "2")})@ResponseBodypublic String hello() throws InterruptedException { return "helloWorld";}代码解释:第 2 行,我们通过配置 HystrixCommand 注解的 threadPoolKey 属性来为本接口分配一个名称为 HelloHystrix 的线程池。第 3 行,我们通过配置 threadPoolProperties 中的参数属性,来维护 HelloHystrix 线程池中的核心线程数量、最大线程数量。通过添加上述注解并配置其中的属性,我们就可以通过线程池隔离的方式来实现服务资源隔离。Tips: 线程池中的线程数量,一定要根据该接口所实现的业务需求来设置,设置过多,则会浪费资源空间,设置过少,则不能支撑业务需要,所以配置线程数量一定要谨慎。
- 1. 多线程的基本概念 程序要完成两个任务:任务 1 进行一项复杂的计算,需要 1 秒才能完成。任务 2 读取磁盘,需要 1 秒才能完成。我们可以串行的执行这两项任务,先执行任务 1,再执行任务 2,完成这两项任务总共需要 2 秒,如下图所示:我们可以并行的执行这两项任务,同时执行这两项任务,完成这两项任务只需要 1 秒,如下图所示:显然,并行执行的时间小于串行执行的时间。很多场景下,我们希望程序能够同时执行多个任务,操作系统提供了多线程的机制用于实现并行执行多个任务。在操作系统中,线程是一个可以独立执行的任务。程序执行时至少包含一个线程,可以使用线程相关的 API 创建新的线程。Python 的 threading 模块提供了类 Thread,用户通过新建一个类 Thread 创建新的线程,本文描述了类 Thread 的基本使用。
- 3. 每线程模型 下图展示了每线程模型的结构。从图中可以看出,每线程模型的程序结构如下:创建一个监听线程,通常会采用 Java 主线程作为监听线程。创建一个 java.net.ServerSocket 实例,调用它的 accept 方法等待客户端的连接。当有新的客户端和服务器建立连接,accept 方法会返回,创建一个新的线程和客户端通信。此时监听线程返回,继续调用 accept 方法,等待新的客户端连接。在新线程中调用 java.net.Socket 的 recv 和 send 方法和客户端进行数据收发。当数据收发完成后,调用 java.net.Socket 的 close 方法关闭连接,同时线程退出。下来,我们通过一个简单的示例程序演示一下每线程模型服务器的编写方法。示例程序的基本功能如下:客户端每隔 1 秒向服务器发送一个消息。服务器收到客户端的消息后,向客户端发送一个响应消息。客户端发送完 10 个消息后,关闭 Socket 连接,程序退出。服务器检测到客户端关闭连接后,同样关闭 Socket 连接,并且负责和客户端通信的线程也退出。客户端代码:import java.io.*;import java.net.InetSocketAddress;import java.net.Socket;import java.net.SocketAddress;public class TCPClientMultiThread { // 服务器监听的端口号 private static final int PORT = 56002; // 连接超时时间 private static final int TIMEOUT = 15000; // 客户端执行次数 private static final int TEST_TIMES = 10; public static void main(String[] args) { Socket client = null; try { // 测试次数 int testCount = 0; // 调用无参构造方法 client = new Socket(); // 构造服务器地址结构 SocketAddress serverAddr = new InetSocketAddress("192.168.0.101", PORT); // 连接服务器,超时时间是 15 毫秒 client.connect(serverAddr, TIMEOUT); System.out.println("Client start:" + client.getLocalSocketAddress().toString()); while (true) { // 向服务器发送数据 DataOutputStream out = new DataOutputStream( new BufferedOutputStream(client.getOutputStream())); String req = "Hello Server!"; out.writeInt(req.getBytes().length); out.write(req.getBytes()); // 不能忘记 flush 方法的调用 out.flush(); System.out.println("Send to server:" + req); // 接收服务器的数据 DataInputStream in = new DataInputStream( new BufferedInputStream(client.getInputStream())); int msgLen = in.readInt(); byte[] inMessage = new byte[msgLen]; in.read(inMessage); System.out.println("Recv from server:" + new String(inMessage)); // 如果执行次数已经达到上限,结束测试。 if (++testCount >= TEST_TIMES) { break; } // 等待 1 秒然后再执行 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } catch (IOException e) { e.printStackTrace(); } finally { if (client != null){ try { client.close(); } catch (IOException e) { e.printStackTrace(); } } } }}服务器代码:import java.io.*;import java.net.ServerSocket;import java.net.Socket;public class TCPServerPerThread implements Runnable{ private static final int PORT =56002; private Socket sock = null; TCPServerPerThread(Socket sock){ this.sock = sock; } @Override public void run() { // 读取客户端数据 try { while (true){ // 读取客户端数据 DataInputStream in = new DataInputStream( new BufferedInputStream(sock.getInputStream())); int msgLen = in.readInt(); byte[] inMessage = new byte[msgLen]; in.read(inMessage); System.out.println("Recv from client:" + new String(inMessage) + "length:" + msgLen); // 向客户端发送数据 String rsp = "Hello Client!\n"; DataOutputStream out = new DataOutputStream( new BufferedOutputStream(sock.getOutputStream())); out.writeInt(rsp.getBytes().length); out.write(rsp.getBytes()); out.flush(); System.out.println("Send to client:" + rsp + " length:" + rsp.getBytes().length); } } catch (IOException e) { e.printStackTrace(); } finally { if (sock != null){ try { sock.close(); } catch (IOException e) { e.printStackTrace(); } } } } public static void main(String[] args) { ServerSocket ss = null; try { // 创建一个服务器 Socket ss = new ServerSocket(PORT); while (true){ // 监听新的连接请求 Socket conn = ss.accept(); System.out.println("Accept a new connection:" + conn.getRemoteSocketAddress().toString()); Thread t = new Thread(new TCPServerPerThread(conn)); t.start(); } } catch (IOException e) { e.printStackTrace(); } finally { if (ss != null){ try { ss.close(); } catch (IOException e) { e.printStackTrace(); } } } }}客户端采用单线程模型。服务器采用每线程模型,我们采用实现 Runnable 接口的方式实现多线程逻辑。从示例代码可以看出,每线程模型的优点就是结构简单,相比单线程模型,也没有增加复杂度。缺点就是针对每个客户端都创建线程,当和客户端通信结束后,线程要退出。频繁的创建、销毁线程,对系统的资源消耗比较大,只能用在简单的业务场景下。
- 2.5 服务提供者上下线测试 首先我们来测试服务下线的情况,服务提供者下线分为两种情况,一种是服务出现故障,与 Zookeeper 服务端断开连接时,另一种是业务需求手动对服务进行下线处理。服务停机我们先来测试服务停机时的情况,这里我们手动关闭端口为 8092 的服务,模拟服务停机,等待会话超时,Zookeeper 服务端就会移除会话失效的临时节点,然后再次访问服务消费者的接口 http://localhost:9090/consumer/callMethod :调用了服务提供者 192.168.0.102:8090 的方法刷新页面,再次访问:调用了服务提供者 192.168.0.102:8091 的方法再次刷新页面进行访问:调用了服务提供者 192.168.0.102:8090 的方法我们发现端口为 8092 的服务已经无法被访问了,但是服务消费者并没有发生异常,说明服务下线成功。这里我们还可以在节点监听的回掉方法中发送短信或邮件通知系统管理员,提醒他们服务下线了。接下来我们测试手动把服务提供者下线的情况。手动下线如果某个服务需要手动下线,我们就可以访问我们在服务提供者中提供的下线方法,这里我们把端口为 8091 的服务下线,访问 http://localhost:8091/provider/offline ,查看浏览器:>>> 服务提供者 192.168.0.102:8091 已下线我们发现端口为 8091 的服务已经下线了,手动下线的情况我们不需要等待会话超时,因为这个会话还存活着,接下来我们就可以再次访问服务消费者的接口 http://localhost:9090/consumer/callMethod :调用了服务提供者 192.168.0.102:8090 的方法我们发现现在只有端口为 8090 的服务能提供服务了,说明服务下线成功了。测试完服务下线的情况,我们来对服务进行上线测试,上线也同样分为两种情况,一种是停机的服务重新启动成功时会注册自身的地址到 Zookeeper 服务,另一种是把手动下线的服务手动进行上线,手动上线的过程同样是注册自身的地址信息到 Zookeeper 服务,接下来我们就同时测试上面两种服务上线的情况。服务启动 + 手动上线首先我们启动上面停机的 8092 服务,然后调用端口为 8091 的手动上线方法 http://localhost:8091/provider/online ,执行完成后,我们就可以使用服务消费着来进行测试了,调用服务消费者的接口 http://localhost:9090/consumer/callMethod 查看浏览器内容:调用了服务提供者 192.168.0.102:8090 的方法刷新页面,再次访问:调用了服务提供者 192.168.0.102:8091 的方法再次刷新页面进行访问:调用了服务提供者 192.168.0.102:8092 的方法我们可以发现,服务消费者依次调用了 8090 ,8091 ,8092 这 3 个服务提供者的方法,并且实现了轮询的负载均衡策略,说明我们的服务上线成功
多线程Python服务器相关搜索
-
daima
damain
dart
dataset
datasource
datediff
datediff函数
datepicker
datetime
db4o
dbi
dcloud
deallocate
debian安装
debugger
debugging
declaration
declarations
declare
decode函数