(IOをブロックする)IOをブロック
Linuxでは、デフォルトでは、すべてのソケットは、このような何かを、典型的な読み出し動作プロセスをブロックしています。
ユーザプロセスがのrecvfromシステムコールを呼び出すと、カーネルカーネルはIOの最初のフェーズを開始しました:データを準備します。ネットワークIO(ネットワークIO)の場合、データの先頭に多くの時間は、(例えば、まだ完全なUDPパケットを受信していない)に達していない、この時間カーネル(カーネル)が来るのに十分なデータを待ちます。
独自のオペレーティングシステムメモリに他のデータを待っています
プロセスユーザ側では、全体のプロセスがブロックされます。データの準備ができているカーネル待ちまでと、それはユーザ・アプリケーション・メモリへのオペレーティングシステムのカーネルバッファからデータをコピーし、します
し、再度起動して実行、ブロックの状態を持ち上げる前に、結果カーネル、ユーザプロセスを返します。
これは、ブロッキングIOです
したがって、ブロッキングIO機能は、IOがブロックされている(二段階でデータのデータコピーを待っている)は、2つの段階で実行されます。
すべてのネットワークプログラミングは\送って、(\)\聞く (\)、のrecv \(\)が最初のインタフェースと、
簡単にこれらのインタフェースを使用してサーバーを構築することができます / モデルクライアントを。しかし、ソケットインタフェースのほとんどは、ブロッキングされています。示されているように
PSを:
いわゆる閉塞性インターフェースは、システムコール(通常はIOインターフェイス)呼び出しの結果を返し、現在のスレッドがブロックされていることはできませんを参照する
システムコールは、結果を取得するときのみ、またはタイムアウトエラーが返されます。
サーバー:
ソケットインポート *の サーバー = ソケット(AF_INET、SOCK_STREAM) server.bind((' 127.0.0.1 '、8000 )) server.listen( 5 ) 中:トゥルー プリント(" ...開始" ) CONN、ADDR = サーバー。 ()受け入れ プリント(ADDR)の 中に真: 試す: データ = conn.recv(1024 ) の場合 ではないデータ:ブレーク conn.send(data.upper()) 除く:ConnectionResetError ブレーク server.close()
クライアント
ソケットのインポート * クライアント = ソケット(AF_INET、SOCK_STREAM) client.connect((' 127.0.0.1 '、8000 )) しばらく真: MSG =入力(" >>>:" ).strip() の場合 ではない:MSG 続ける クライアント.send(msg.encode(" UTF-8 " )) データ = client.recv(1024 ) プリント(data.decode(" UTF-8 " )) client.close()
实际上,除非特别指定,几乎所有的IO接口 ( 包括socket接口 ) 都是阻塞型的。这给网络编程带来了一个很大的问题,如在调用recv(1024)的同时,线程将被阻塞,在此期间,线程将无法执行任何运算或响应任何的网络请求。
一个简单的解决方案:
在服务器端使用多线程(或多进程)。多线程(或多进程)的目的是让每个连接都拥有独立的线程(或进程),
这样任何一个连接的阻塞都不会影响其他的连接。
该方案的问题是 :
开启多进程或都线程的方式,在遇到要同时响应成百上千路的连接请求,则无论多线程还是多进程都会严重占据系统资源,
降低系统对外界响应效率,而且线程与进程本身也更容易进入假死状态。
随着客户端数量增多,无限制的开线程,开销非常大
不能解决阻塞IO问题 ,解决思路:起多线程
改进方案:
使用“线程池”或“连接池”。“线程池”旨在减少创建和销毁线程的频率,
其维持一定合理数量的线程,并让空闲的线程重新承担新的执行任务。“连接池”维持连接的缓存池,尽量重用已有的连接、
减少创建和关闭连接的频率。这两种技术都可以很好的降低系统开销,都被广泛应用很多大型系统,如websphere、tomcat和各种数据库等。
改进后方案其实也存在着问题:
“线程池”和“连接池”技术也只是在一定程度上缓解了频繁调用IO接口带来的资源占用。而且,所谓“池”始终是有限,
当请求大大超过上限时,“池”构成的系统对外界的响应并不比没有池的时候效果好多少。所以使用“池”必须考虑其面临的响应规模,
并根据响应规模调整“池”的大小。
线程池应该随着规模数调大,但是调大线程池,要在机器可承受范围之内。不能把线程池无限调大,这样相当于无限开线程一样,
多线程还是要用在规模比较小的情况
对应上例中的所面临的可能同时出现的上千甚至上万次的客户端请求,“线程池”或“连接池”或许可以缓解部分压力,但是不能解决所有问题。总之,多线程模型可以方便高效的解决小规模的服务请求,但面对大规模的服务请求,多线程模型也会遇到瓶颈,可以用非阻塞接口来尝试解决这个问题。
总结:
始综没有解决单线程遇到IO问题,单线程遇到IO,就阻塞,用的是阻塞IO模型。
阻塞IO模型就是遇到IO阻塞不处理,就在原地等着。
应该:
监测单线程IO,遇到IO了,这个线程不要阻塞。直接切换到另外一个线程运行,这样单线程效率就非常高了。
要解决的问题是:
单线程IO问题