Ⅰ C語言 阻塞、非阻塞和多線程有什麼關系
說到阻塞和非阻塞 的概念,就要了解同步和非同步的概念吧
同步:多個線程可以同時訪問同一個資源。比如對一個變數而言,線程們可以同時對他進行讀寫。
使用場景:多個線程同時訪問一塊數據,也叫共享區。對於多個線程同時訪問一塊數據的時候,必須使用同步,否則可能會出現不安全的情況。比如資料庫中的臟讀。但是,多個線程同時訪問一塊數據,有一種情況不需要同步技術,那就是原子操作,也就是說操作系統在底層保證了操作要麼全部做完,要麼不做。
非同步:
使用場景:只有一個線程訪問當前的數據。比如,觀察者模式,沒有共享區,主題發生變化,通知觀察者更新,主題繼續做自己的事情,不需要等待觀察者更新完成後再工作。
同步分為阻塞IO和非同步IO
非同步可以分為阻塞IO和非阻塞的IO
非同步阻塞IO 通過select和epoll實現
Ⅱ 既然消息組件可以實現非同步非阻塞,那麼為什麼還要用netty呢
兩種技術解決的問題不同。
netty解決的是不同協議的編程:http,tcp(尤其是這個)編程
消息組件解決【處理能力】小於【請求能力】,使用消息組件在兩者之間建立一個緩沖
Ⅲ nodejs和非阻塞io 和非同步的區別
阻塞I/O
程序執行程必要進行I/O操作讀寫文件、輸入輸、請求響應等等I/O操作費至少相於代碼說傳統編程模式舉例要讀文件整線程都暫停等待文件讀完繼續執行換言I/O操作阻塞代碼執行極降低程序效率
面C#讀文件例:
private string ReadTxtToStr(string filename)
{
//打文件,打期間其代碼停止執行直完打繼續執行代碼
FileStream fs = File.Open(filename, FileMode.Open);
Console.WriteLine("我打文件阻塞");
StreamReader sr = new StreamReader(fs);
//讀取文件讀取期間其代碼停止執行直完讀取繼續執行代碼
string str=sr.ReadToEnd();
Console.WriteLine("我讀取文件阻塞");
return str;
}
述代碼兩Console.WriteLine()雖執行卻辜阻塞段間理論讀取文件需要10秒我浪費10秒I/O等待(實際程序運行部間浪費I/O等待)碼農眼文數字
Having asynchronous I/O is good, because I/O is more expensive than most code and we should be doing something better than just waiting for I/O.
非阻塞I/O
理解阻塞I/O非阻塞I/O理解非阻塞I/O程序執行程I/O操作阻塞程序執行I/O操作同繼續執行其代碼(益於Node事件循環機制)I/O設備效率遠遠低於CPU效率代種I/O模型(非阻塞I/O)程序帶性能提高非觀
面受用Node.js實現非阻塞I/O繼續讀文件看碼:
var fs = require("fs");
fs.readFile("./testfile", "utf8", function(error, file) {
if (error) throw error;
console.log("我讀完文件");
});
console.log("我阻塞");
復制面代碼保存test.js並同目錄新建名testfile文件用node命令運行test.js,看輸:
我阻塞
我讀完文件
顯符合傳統程序執行順序注意Node.js非阻塞I/O
首先解釋面程序熟悉javaScript請忽略
var fs = require("fs");
代碼:引入Node.js內置File System文件系統模塊fsrequire()相與JavaimportC++include
fs.readFile("./testfile", "utf8", function(error, file) {
if (error) throw error;
console.log("我讀完文件");
});
代碼:進行I/O操作給readFile綁定調函數function(error,file){},並讀取testfile完執行調函數期間面代碼繼續執行受I/O阻塞
先看我阻塞看我讀完文件緣故
Node.js事件輪詢機制(event loop)
《Node入門》推薦我讀Mixu篇關於事件輪詢博文確值讀我英語般著詞典能勉強看略懂吧
Mixu說經典句:
Everything runs in parallel except your code!
(Node)除代碼切都並行
理解句再Node事半功倍
-
Ⅳ 名詞解釋:同步、非同步、阻塞和非阻塞
同步1.同時起步,協調一致。 2.物理學名詞。兩個或幾個隨時間變化的量,在變化過程中保持一定的相對關系. 非同步則反之..
阻塞 1.水流、交通等因被某物堵塞而不能通過。 2.閉塞不通。 3.使堵塞不通。用於抽象事物。 非阻塞則反之
Ⅳ 怎樣理解阻塞非阻塞與同步非同步的區別
「阻塞」與"非阻塞"與"同步"與「非同步"不能簡單的從字面理解,提供一個從分布式系統角度的回答。
1.同步與非同步
同步和非同步關注的是消息通信機制 (synchronous communication/ asynchronous communication)
所謂同步,就是在發出一個*調用*時,在沒有得到結果之前,該*調用*就不返回。但是一旦調用返回,就得到返回值了。
換句話說,就是由*調用者*主動等待這個*調用*的結果。
而非同步則是相反,*調用*在發出之後,這個調用就直接返回了,所以沒有返回結果。換句話說,當一個非同步過程調用發出後,調用者不會立刻得到結果。而是在*調用*發出後,*被調用者*通過狀態、通知來通知調用者,或通過回調函數處理這個調用。
典型的非同步編程模型比如Node.js
舉個通俗的例子:
你打電話問書店老闆有沒有《分布式系統》這本書,如果是同步通信機制,書店老闆會說,你稍等,」我查一下",然後開始查啊查,等查好了(可能是5秒,也可能是一天)告訴你結果(返回結果)。
而非同步通信機制,書店老闆直接告訴你我查一下啊,查好了打電話給你,然後直接掛電話了(不返回結果)。然後查好了,他會主動打電話給你。在這里老闆通過「回電」這種方式來回調。
2. 阻塞與非阻塞
阻塞和非阻塞關注的是程序在等待調用結果(消息,返回值)時的狀態.
阻塞調用是指調用結果返回之前,當前線程會被掛起。調用線程只有在得到結果之後才會返回。
非阻塞調用指在不能立刻得到結果之前,該調用不會阻塞當前線程。
還是上面的例子,
你打電話問書店老闆有沒有《分布式系統》這本書,你如果是阻塞式調用,你會一直把自己「掛起」,直到得到這本書有沒有的結果,如果是非阻塞式調用,你不管老闆有沒有告訴你,你自己先一邊去玩了, 當然你也要偶爾過幾分鍾check一下老闆有沒有返回結果。
在這里阻塞與非阻塞與是否同步非同步無關。跟老闆通過什麼方式回答你結果無關。
Ⅵ 為什麼說nodejs是非同步非阻塞
阻塞I/O
程序執行過程中必然要進行很多I/O操作,讀寫文件、輸入輸出、請求響應等等。I/O操作時最費時的,至少相對於代碼來說,在傳統的編程模式中,舉個例子,你要讀一個文件,整個線程都暫停下來,等待文件讀完後繼續執行。換言之,I/O操作阻塞了代碼的執行,極大地降低了程序的效率。
下面是是一個C#讀文件的例子:
private string ReadTxtToStr(string filename)
{
//打開文件,打開期間其他代碼停止執行,直到完成打開後繼續執行代碼。
FileStream fs = File.Open(filename, FileMode.Open);
Console.WriteLine("我被打開文件阻塞了。");
StreamReader sr = new StreamReader(fs);
//讀取文件,讀取期間其他代碼停止執行,直到完成讀取後繼續執行代碼。
string str=sr.ReadToEnd();
Console.WriteLine("我被讀取文件阻塞了。");
return str;
}
在上述代碼中,兩個Console.WriteLine()雖然會被執行,但是卻被無辜地阻塞一段時間。理論上,如果讀取這個文件需要10秒,我們就浪費了10秒在I/O等待中(實際程序運行中有很大一部分時間是浪費在I/O等待上的),在碼農眼裡這可是天文數字。
Having asynchronous I/O is good, because I/O is more expensive than most code and we should be doing something better than just waiting for I/O.
非阻塞I/O
理解了阻塞I/O,非阻塞I/O就好理解。非阻塞I/O是程序執行過程中,I/O操作不會阻塞程序的執行,也就是在I/O操作的同時,繼續執行其他代碼(這得益於Node的事件循環機制)。在I/O設備效率還遠遠低於CPU效率的時代,這種I/O模型(非阻塞I/O)為程序帶來的性能上的提高是非常可觀的。
好,下面感受一下怎麼用Node.js實現非阻塞I/O,繼續讀文件,看碼:
var fs = require("fs");
fs.readFile("./testfile", "utf8", function(error, file) {
if (error) throw error;
console.log("我讀完文件了!");
});
console.log("我不會被阻塞!");
復制上面代碼保存為test.js,並在同一目錄下新建一個名為testfile的文件,用node命令運行test.js,你將看到以下輸出:
我不會被阻塞!
我讀完文件了!
這顯然不符合傳統的程序執行順序,注意,這就是Node.js的非阻塞I/O了。
首先解釋下面程序,如果你熟悉JavaScript,請忽略。
var fs = require("fs");
以上代碼:引入Node.js內置的File System文件系統模塊fs。require()相當與Java的import,C++的include。
fs.readFile("./testfile", "utf8", function(error, file) {
if (error) throw error;
console.log("我讀完文件了!");
});
以上代碼:進行I/O操作,給readFile綁定一個回調函數function(error,file){},並在讀取testfile完成後執行回調函數。期間,後面的代碼繼續執行,不受I/O阻塞。
這就是為什麼先看到「我不會被阻塞!」而後看到「我讀完文件了!」的緣故。
Node.js事件輪詢機制(event loop)
《Node入門》推薦我們去讀一下Mixu的一篇關於事件輪詢的博文,的確值得一讀,我英語一般,開著詞典還能勉強看,略懂吧。
Mixu說的最經典的一句話:
Everything runs in parallel except your code!
(在Node中)除了代碼,一切都是並行的!
理解這句話,再去學Node,也就事半功倍了!
Ⅶ java 非同步編程
用非同步輸入輸出流編寫Socket進程通信程序
在Merlin中加入了用於實現非同步輸入輸出機制的應用程序介麵包:java.nio(新的輸入輸出包,定義了很多基本類型緩沖(Buffer)),java.nio.channels(通道及選擇器等,用於非同步輸入輸出),java.nio.charset(字元的編碼解碼)。通道(Channel)首先在選擇器(Selector)中注冊自己感興趣的事件,當相應的事件發生時,選擇器便通過選擇鍵(SelectionKey)通知已注冊的通道。然後通道將需要處理的信息,通過緩沖(Buffer)打包,編碼/解碼,完成輸入輸出控制。
通道介紹:
這里主要介紹ServerSocketChannel和 SocketChannel.它們都是可選擇的(selectable)通道,分別可以工作在同步和非同步兩種方式下(注意,這里的可選擇不是指可以選擇兩種工作方式,而是指可以有選擇的注冊自己感興趣的事件)。可以用channel.configureBlocking(Boolean )來設置其工作方式。與以前版本的API相比較,ServerSocketChannel就相當於ServerSocket(ServerSocketChannel封裝了ServerSocket),而SocketChannel就相當於Socket(SocketChannel封裝了Socket)。當通道工作在同步方式時,編程方法與以前的基本相似,這里主要介紹非同步工作方式。
所謂非同步輸入輸出機制,是指在進行輸入輸出處理時,不必等到輸入輸出處理完畢才返回。所以非同步的同義語是非阻塞(None Blocking)。在伺服器端,ServerSocketChannel通過靜態函數open()返回一個實例serverChl。然後該通道調用serverChl.socket().bind()綁定到伺服器某埠,並調用register(Selector sel, SelectionKey.OP_ACCEPT)注冊OP_ACCEPT事件到一個選擇器中(ServerSocketChannel只可以注冊OP_ACCEPT事件)。當有客戶請求連接時,選擇器就會通知該通道有客戶連接請求,就可以進行相應的輸入輸出控制了;在客戶端,clientChl實例注冊自己感興趣的事件後(可以是OP_CONNECT,OP_READ,OP_WRITE的組合),調用clientChl.connect(InetSocketAddress )連接伺服器然後進行相應處理。注意,這里的連接是非同步的,即會立即返回而繼續執行後面的代碼。
選擇器和選擇鍵介紹:
選擇器(Selector)的作用是:將通道感興趣的事件放入隊列中,而不是馬上提交給應用程序,等已注冊的通道自己來請求處理這些事件。換句話說,就是選擇器將會隨時報告已經准備好了的通道,而且是按照先進先出的順序。那麼,選擇器是通過什麼來報告的呢?選擇鍵(SelectionKey)。選擇鍵的作用就是表明哪個通道已經做好了准備,准備干什麼。你也許馬上會想到,那一定是已注冊的通道感興趣的事件。不錯,例如對於伺服器端serverChl來說,可以調用key.isAcceptable()來通知serverChl有客戶端連接請求。相應的函數還有:SelectionKey.isReadable(),SelectionKey.isWritable()。一般的,在一個循環中輪詢感興趣的事件(具體可參照下面的代碼)。如果選擇器中尚無通道已注冊事件發生,調用Selector.select()將阻塞,直到有事件發生為止。另外,可以調用selectNow()或者select(long timeout)。前者立即返回,沒有事件時返回0值;後者等待timeout時間後返回。一個選擇器最多可以同時被63個通道一起注冊使用。
應用實例:
下面是用非同步輸入輸出機制實現的客戶/伺服器實常式序――程序清單1(限於篇幅,只給出了伺服器端實現,讀者可以參照著實現客戶端代碼):
程序類圖
public class NBlockingServer {
int port = 8000;
int BUFFERSIZE = 1024;
Selector selector = null;
ServerSocketChannel serverChannel = null;
HashMap clientChannelMap = null;//用來存放每一個客戶連接對應的套接字和通道
public NBlockingServer( int port ) {
this.clientChannelMap = new HashMap();
this.port = port;
}
public void initialize() throws IOException {
//初始化,分別實例化一個選擇器,一個伺服器端可選擇通道
this.selector = Selector.open();
this.serverChannel = ServerSocketChannel.open();
this.serverChannel.configureBlocking(false);
InetAddress localhost = InetAddress.getLocalHost();
InetSocketAddress isa = new InetSocketAddress(localhost, this.port );
this.serverChannel.socket().bind(isa);//將該套接字綁定到伺服器某一可用埠
}
//結束時釋放資源
public void finalize() throws IOException {
this.serverChannel.close();
this.selector.close();
}
//將讀入位元組緩沖的信息解碼
public String decode( ByteBuffer byteBuffer ) throws
CharacterCodingException {
Charset charset = Charset.forName( "ISO-8859-1" );
CharsetDecoder decoder = charset.newDecoder();
CharBuffer charBuffer = decoder.decode( byteBuffer );
String result = charBuffer.toString();
return result;
}
//監聽埠,當通道准備好時進行相應操作
public void portListening() throws IOException, InterruptedException {
//伺服器端通道注冊OP_ACCEPT事件
SelectionKey acceptKey =this.serverChannel.register( this.selector,
SelectionKey.OP_ACCEPT );
//當有已注冊的事件發生時,select()返回值將大於0
while (acceptKey.selector().select() > 0 ) {
System.out.println("event happened");
//取得所有已經准備好的所有選擇鍵
Set readyKeys = this.selector.selectedKeys();
//使用迭代器對選擇鍵進行輪詢
Iterator i = readyKeys.iterator();
while (i
else if ( key.isReadable() ) {//如果是通道讀准備好事件
System.out.println("Readable");
//取得選擇鍵對應的通道和套接字
SelectableChannel nextReady =
(SelectableChannel) key.channel();
Socket socket = (Socket) key.attachment();
//處理該事件,處理方法已封裝在類ClientChInstance中
this.readFromChannel( socket.getChannel(),
(ClientChInstance)
this.clientChannelMap.get( socket ) );
}
else if ( key.isWritable() ) {//如果是通道寫准備好事件
System.out.println("writeable");
//取得套接字後處理,方法同上
Socket socket = (Socket) key.attachment();
SocketChannel channel = (SocketChannel)
socket.getChannel();
this.writeToChannel( channel,"This is from server!");
}
}
}
}
//對通道的寫操作
public void writeToChannel( SocketChannel channel, String message )
throws IOException {
ByteBuffer buf = ByteBuffer.wrap( message.getBytes() );
int nbytes = channel.write( buf );
}
//對通道的讀操作
public void readFromChannel( SocketChannel channel, ClientChInstance clientInstance )
throws IOException, InterruptedException {
ByteBuffer byteBuffer = ByteBuffer.allocate( BUFFERSIZE );
int nbytes = channel.read( byteBuffer );
byteBuffer.flip();
String result = this.decode( byteBuffer );
//當客戶端發出」@exit」退出命令時,關閉其通道
if ( result.indexOf( "@exit" ) >= 0 ) {
channel.close();
}
else {
clientInstance.append( result.toString() );
//讀入一行完畢,執行相應操作
if ( result.indexOf( "\n" ) >= 0 ){
System.out.println("client input"+result);
clientInstance.execute();
}
}
}
//該類封裝了怎樣對客戶端的通道進行操作,具體實現可以通過重載execute()方法
public class ClientChInstance {
SocketChannel channel;
StringBuffer buffer=new StringBuffer();
public ClientChInstance( SocketChannel channel ) {
this.channel = channel;
}
public void execute() throws IOException {
String message = "This is response after reading from channel!";
writeToChannel( this.channel, message );
buffer = new StringBuffer();
}
//當一行沒有結束時,將當前字竄置於緩沖尾
public void append( String values ) {
buffer.append( values );
}
}
//主程序
public static void main( String[] args ) {
NBlockingServer nbServer = new NBlockingServer(8000);
try {
nbServer.initialize();
} catch ( Exception e ) {
e.printStackTrace();
System.exit( -1 );
}
try {
nbServer.portListening();
}
catch ( Exception e ) {
e.printStackTrace();
}
}
}
程序清單1
小結:
從以上程序段可以看出,伺服器端沒有引入多餘線程就完成了多客戶的客戶/伺服器模式。該程序中使用了回調模式(CALLBACK)。需要注意的是,請不要將原來的輸入輸出包與新加入的輸入輸出包混用,因為出於一些原因的考慮,這兩個包並不兼容。即使用通道時請使用緩沖完成輸入輸出控制。該程序在Windows2000,J2SE1.4下,用telnet測試成功。
Ⅷ 網路編程中阻塞和非阻塞socket的區別
阻塞:一般的I/O操作可以在新建的流中運用.在伺服器回應前它等待客戶端發送一個空白的行.當會話結束時,伺服器關閉流和客戶端socket.如果在隊列中沒有請示將會出現什麼情況呢?那個方法將會等待一個的到來.這個行為叫阻塞.accept()方法將會阻塞伺服器線程直到一個呼叫到來.當5個連接處理完閉之後,伺服器退出.任何的在隊列中的呼叫將會被取消.
非阻塞:非阻塞套接字是指執行此套接字的網路調用時,不管是否執行成功,都立即返回。比如調用recv()函數讀取網路緩沖區中數據,不管是否讀到數據都立即返回,而不會一直掛在此函數調用上。在實際Windows網路通信軟體開發中,非同步非阻塞套接字是用的最多的。平常所說的C/S(客戶端/伺服器)結構的軟體就是非同步非阻塞模式的