python blocking IO concurrent programming model

 

 

Blocking IO (blocking IO)

In linux, by default, all socket is blocking, a typical read operation process something like this:

When the user process calls the recvfrom system call, kernel kernel began the first phase of the IO: Prepare data. For network io (network io), a lot of time at the beginning of the data has not reached (for example, has not yet received a complete UDP packet), this time kernel (kernel) will wait for enough data to come.

Waiting for the other data into its own operating system memory

 

In the process the user side, the whole process will be blocked. When the kernel wait until the data is ready, it will copy the data from the operating system kernel buffer to the user application memory, 
and then returns the result kernel, the user process before lifting the state of the block, up and running again.

This is the blocking IO

 

Therefore, blocking IO feature is executed in two stages IO (waiting for data and copies of data in two stages) are the block

Network programming from all listen \ (\), send \ (\), recv \ (\) interfaces the beginning, 
you can easily build server using these interfaces / model client. However, most of the socket interface are blocking. As shown 

ps: 
the so-called obstructive interface refers to the system call (usually IO interface) does not return a result of the call and let the current thread has been blocked 
only when the system call to get the result or a timeout error is returned.

 

Server:

from socket import *

server = socket(AF_INET,SOCK_STREAM)
server.bind(('127.0.0.1',8000))
server.listen(5)

while True:
    print("starting...")
    conn,addr = server.accept()
    print(addr)

    while True:
        try:
            data = conn.recv(1024)
            if not data:break
            conn.send(data.upper())

        except ConnectionResetError:
            break

server.close()

 

Client

from socket import *

client = socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8000))

while True:
    msg = input(">>>:").strip()
    if not msg:continue
    client.send(msg.encode("utf-8"))
    data = client.recv(1024)
    print(data.decode("utf-8"))


client.close()

 

 

 

 

实际上,除非特别指定,几乎所有的IO接口 ( 包括socket接口 ) 都是阻塞型的。这给网络编程带来了一个很大的问题,如在调用recv(1024)的同时,线程将被阻塞,在此期间,线程将无法执行任何运算或响应任何的网络请求。

一个简单的解决方案:

在服务器端使用多线程(或多进程)。多线程(或多进程)的目的是让每个连接都拥有独立的线程(或进程),
这样任何一个连接的阻塞都不会影响其他的连接。

 

该方案的问题是 :

开启多进程或都线程的方式,在遇到要同时响应成百上千路的连接请求,则无论多线程还是多进程都会严重占据系统资源,
降低系统对外界响应效率,而且线程与进程本身也更容易进入假死状态。
随着客户端数量增多,无限制的开线程,开销非常大

不能解决阻塞IO问题 ,解决思路:起多线程

 

改进方案:

使用“线程池”或“连接池”。“线程池”旨在减少创建和销毁线程的频率,
其维持一定合理数量的线程并让空闲的线程重新承担新的执行任务。“连接池”维持连接的缓存池,尽量重用已有的连接、
减少创建和关闭连接的频率。这两种技术都可以很好的降低系统开销,都被广泛应用很多大型系统,如websphere、tomcat和各种数据库等。

 

 

改进后方案其实也存在着问题:

“线程池”和“连接池”技术也只是在一定程度上缓解了频繁调用IO接口带来的资源占用。而且,所谓“池”始终是有限,
当请求大大超过上限时,“池”构成的系统对外界的响应并不比没有池的时候效果好多少。所以使用“池”必须考虑其面临的响应规模,
并根据响应规模调整“池”的大小。

线程池应该随着规模数调大,但是调大线程池,要在机器可承受范围之内。不能把线程池无限调大,这样相当于无限开线程一样,

多线程还是要用在规模比较小的情况

 

 

对应上例中的所面临的可能同时出现的上千甚至上万次的客户端请求,“线程池”或“连接池”或许可以缓解部分压力,但是不能解决所有问题。总之,多线程模型可以方便高效的解决小规模的服务请求,但面对大规模的服务请求,多线程模型也会遇到瓶颈,可以用非阻塞接口来尝试解决这个问题

 

总结:

始综没有解决单线程遇到IO问题,单线程遇到IO,就阻塞,用的是阻塞IO模型。

阻塞IO模型就是遇到IO阻塞不处理,就在原地等着。

应该:

监测单线程IO,遇到IO了,这个线程不要阻塞。直接切换到另外一个线程运行,这样单线程效率就非常高了。

要解决的问题是:

单线程IO问题

 

Guess you like

Origin www.cnblogs.com/mingerlcm/p/11181351.html