2020.8.27
一直不明白为什么网络socket编程默认都是阻塞的,阻塞了程序不就停了不响应了吗,好纠结。
现在有点了解了,阻塞时是等待状态,类似于内核把它sleep,不占用CPU,对操作系统正常运转是非常有利的。
非阻塞方式:程序不会停止响应,socket函数会马上返回,但程序需要一直轮询socket,如果socket没有动作,那其实就是在while(1)啊,CPU占用是100%啊。不行啊,操作系统要完蛋的。
所以还是用阻塞方式吧,内核已经把最优方案给我们了。
但是,一个socket这么用是没问题的,多个socket就麻烦了。
主要有二个方法:
1. 多线程:
一个socket放入一个线程,阻塞了后,线程处于停止状态,不影响主程序和其它socket。
线程程序是按正常socket通讯交互流程走,符合正常编程思路,编程容易些,但开销大,线程多了扛不住。
线程要占用内存,有人试过linux大约是可以开到300个线程,每个线程占10MB,好大。
所以一般十几、几十个socket可以用多线程玩一玩。
2. IO多路复用:select,poll,epoll等。
主程序一个线程就可以处理所有socket。
编程比较麻烦,得判断各个socket是在通讯交互流程的哪一步。
read/recv()取决于对方有没有发来数据,阻塞可能性很大,write/send()则是自己发送数据,一般不阻塞,所以一般只判断读取标志即可,发送则直接用write()或send(),这样程序比较简单。
参考网友说的:
“
qeesung
如果只有一个套接字的情况下,使用阻塞IO是极好的,读到数据就返回。
但是如果在有很多套接字的情况下,比如有100个套接字:
1. 如果使用阻塞IO,可能因为读取一个没有数据的套接字而阻塞剩下的99个套接字的数据处理,那么就会造成服务器的响应性很差。
2. 如果使用非阻塞IO,那么就需要轮询这一百个套接字到底可不可以读取到数据,这个轮询操作会浪费CPU时间片,照样也不是一个高效的方式,套接字多了,照样性能很差。
那有没有一种比较好的方式来同时检测多个套接字是否可读可写,并且不浪费CPU时间片呢?那就是要用IO多路复用了,使用IO多路复用可以同时检测多个不同的套接字是否就绪。有多种IO多路复用的实现,其中包括select,poll, epoll, /dev/poll, kqueue等。
”
————————————————
版权声明:本文为CSDN博主「wxlfreewind」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wxlfreewind/article/details/108274842
2020.8.27一直不明白为什么网络socket编程默认都是阻塞的,阻塞了程序不就停了不响应了吗,好纠结。现在有点了解了,阻塞时是等待状态,类似于内核把它sleep,不占用CPU,对操作系统正常运转是非常有利的。非阻塞方式:程序不会停止响应,socket函数会马上返回,但程序需要一直轮询socket,如果socket没有动作,那其实就是在while(1)啊,CPU占用是100%啊。不行啊,操作系统要完蛋的。所以还是用阻塞方式吧,内核已经把最优方案给我们了。但是,一个socket这么用是没问题的,多个soc
import java.
io
.BufferedReader;
import java.
io
.
IO
Except
io
n;
import java.
io
.InputStreamReader;
import java.
io
.PrintWriter;
第一个概念:用户空间与内核空间
1. 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32次方)
2. 操作系统的核心是内核,独立于普通的应用程序,可以访问受保护的内存空间,也有访问底层硬件设备的所有权限。
3. 为了保证用户进程不能直接操作内核(kernel),保证内核的安全,操心系统将虚拟空间划分为两部分:一部分为内核空间,一部分为用户空间
4. 针对
linux
操作系统而言,将最高的1G字节(从虚拟地
多线程
是程序设计中的一个重要方面,尤其是在
服务器
Deamon程序方面。无论何种系统,线程调度的开销都比传统的进程要快得多。
Python可以方便地支持
多线程
。可以快速创建线程、互斥锁、信号量等等元素,支持线程读写同步互斥。美中不足的是,Python的运行在Python 虚拟机上,创建的
多线程
可能是虚拟的线程,需要由Python虚拟机来
轮询
调度,这大大降低了Python
多线程
的可用性。希望高版本的Python可以 解决这个问题,发挥多
CPU
的最大效率。
网上有些朋友说要获得真正多
CPU
的好处,有两种方法:
1.可以创建多个进程而不是线程,进程数和
cpu
一样多。
这种
IO
方式为事件驱动
IO
(event driven
IO
)。
我们都知道,select/epoll的好处就在于单个进程process就可以同时处理多个
网络
连接的
IO
。它的基本原理就是select/epoll这个funct
io
n会不断的
轮询
所负责的所有
socket
,当某个
socket
有数据到达了,就通知用户进程。它的流程如图:
select是多路
复用
的一种
当用户进程调用了select,那么整个进程会被block,而同时,kernel会“监视”所有select负责的
socket
,
当任何一个
socket
中的数据准备好了,select就会返回
1.接手的项目apk中基于JT808协议用
Socket
上传位置等消息,用命令top -m 10 -s
cpu
查看
cpu
消耗时发现此app
占用
cpu
超过10%
先把GPS停了,重新运行还是会很耗
cpu
用Android Profiler查了下点record
最终定位到
线程里
Socket
Channel里的read方法
while (true) {
1、
socket
默认是
阻塞
的,
阻塞
时:
send函数如果可用空间大小小于要发送的数据长度,则send会被
阻塞
,直到缓冲区中的数据被发送到目标主机,有了足够的空间之后,send函数才会将数据写入输出缓冲区。
要写入的数据大于输出缓冲区的最大长度的时候,要分多次写入,直到所有数据都被写到缓冲区之后,send函数才会返回。
recv函数,函数先检查输入缓冲区,如果输入缓冲区中有数据,读取出缓冲区中的数据,否则的话,recv函数会被
阻塞
,等待
网络
上传来数据。如果每次读取的数据长度小于buffer的数据长度.
在用自定义线程池的时候,遇到
cpu
100%,经过验证后,发现问题来源于我定义的子线程。
子线程的主要功能是从任务队列(LinkedBlockingQueue)里面持续拿出任务,并且执行。
以下为令
CPU
100的代码。
private class WorkThread extends Thread
@Override
public void ru...
1.
非阻塞
IO
模型:
- 在
非阻塞
IO
模型中,当应用程序发起一个
IO
操作后,不会
阻塞
等待数据准备好或传输完成,而是立即返回控制权给应用程序,继续执行其他任务。
- 应用程序需要通过
轮询
的方式主动查询
IO
操作的状态,以确定数据是否准备好或传输完成。
-
非阻塞
IO
适用于处理大量的短连接、低并发的情况,但会带来频繁的
轮询
开销,降低了
CPU
利用率。
2. 多路
复用
IO
模型:
- 在多路
复用
IO
模型中,应用程序通过将多个
IO
操作注册到一个统一的事件管理器(如select、poll、epoll等),然后将控制权交给操作系统。
- 操作系统负责监听所有注册的
IO
事件,并在有事件发生时通知应用程序进行处理。
- 多路
复用
IO
模型使用事件通知机制,应用程序只需要等待事件通知,并处理已触发的事件,显著降低了
轮询
开销和系统资源
占用
。
- 多路
复用
IO
适用于处理高并发、大量长连接的情况,提高了系统的可扩展性和性能。
非阻塞
IO
模型需要应用程序主动
轮询
IO
状态,适用于低并发的情况;而多路
复用
IO
模型利用操作系统的事件通知机制,避免了频繁的
轮询
开销,适用于高并发的情况。选择哪种
IO
模型取决于应用程序的需求和场景。