當前位置: 妍妍網 > 碼農

同步/ 異步 / 阻塞 / 非阻塞?真把我搞暈了

2024-05-19碼農

引言:本文將深入探討這些I/O操作的核心概念,透過生活中的比喻,將抽象的技術術語轉化為易於理解的日常場景。我們將一起探索同步與異步的通訊機制,理解它們如何在不同的情境下發揮作用,以及阻塞與非阻塞如何影響程式的執行流程。透過這些深入淺出的解析,我們希望能夠幫助讀者更好地理解I/O操作的本質,從而在編程實踐中做出更明智的選擇。

題目

同步、異步、阻塞、非阻塞的IO的區別?

推薦解析

同步和異步概念

同步和異步關註的是訊息通訊機制。

同步,就是在發出一個呼叫時,在沒有得到結果之前,該呼叫就不返回。但是一旦呼叫返回,就得到返回值了。

異步則是相反,呼叫在發出之後,這個呼叫就直接返回了,所以沒有返回結果。

生活舉例

同步:在人工咖啡店點咖啡,排隊等待服務員制作完成,等制作完成之後,才能進行下一步行動。

異步:自助咖啡機等咖啡,可以在等咖啡時做其他事情,例如玩手機,讀雜誌。

同步的舉例很明顯現在已經被最佳化了,因為同步的對人為感覺明顯不好,異步更為舒適。

阻塞和非阻塞概念

阻塞和非阻塞關註程式在等待呼叫結果時的狀態。

阻塞:被呼叫者接受到任務請求,會掛起當前執行緒,執行任務請求,直到完成,然後返回給呼叫者。

非阻塞:被呼叫者,先做完其他的事情,然後開始做呼叫者的任務請求,不會阻塞當前執行緒。

生活舉例

阻塞:交通擁堵的交通路口等待紅綠燈,只有交通訊號燈變綠才能繼續前行,車輛被阻塞。

非阻塞:當你在等待電梯,此時電梯在其他樓層,采用非阻塞方式,可以采用樓梯代替電梯。

Java 程式碼舉例

同步阻塞I/O(BIO)

import java.io.FileInputStream;
import java.io.IOException;
public classSyncBlockingIOExample{
publicstaticvoidmain(String[] args){
try (FileInputStream fis = new FileInputStream("example.txt")) {
int data;
while ((data = fis.read()) != -1) {
// 處理數據
System.out.print((char) data);
}
catch (IOException e) {
e.printStackTrace();
}
}
}

同步非阻塞I/O

import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
public classSyncNonBlockingIOExample{
publicstaticvoidmain(String[] args)throws Exception {
FileChannel channel = FileChannel.open(Paths.get("example.txt"), StandardOpenOption.READ);
ByteBuffer buffer = ByteBuffer.allocate(1024);
while (channel.read(buffer) != -1) {
buffer.flip();
while (buffer.hasRemaining()) {
// 處理數據
System.out.print((char) buffer.get());
}
buffer.clear();
}
channel.close();
}
}

異步I/O(AIO)

import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.Future;
public classAsyncIOExample{
publicstaticvoidmain(String[] args)throws Exception {
AsynchronousFileChannel channel = AsynchronousFileChannel.open(Paths.get("example.txt"), StandardOpenOption.READ);
ByteBuffer buffer = ByteBuffer.allocate(1024);
Future<Integer> result = channel.read(buffer, 0);
while (!result.isDone()) {
// 執行其他任務
}
buffer.flip();
while (buffer.hasRemaining()) {
// 處理數據
System.out.print((char) buffer.get());
}
buffer.clear();
channel.close();
}
}


區別詳解

同步I/O

1) 定義 :同步I/O是指程式發起一個I/O操作後,必須等待該操作完成並獲取到結果後,才能繼續執行後續程式碼。

2) 特點 :同步I/O操作會阻塞程式的執行,直到I/O操作完成。這意味著程式在等待I/O操作期間不能執行其他任務。

3) 範例 :在Java中,使用 java.io 包中的 FileInputStream FileOutputStream 進行檔讀寫就是同步I/O的例子。

異步I/O

1) 定義 :異步I/O是指程式發起一個I/O操作後,不需要等待該操作完成,而是可以繼續執行後續程式碼。I/O操作完成後,程式會透過回呼、事件或輪詢等方式得到通知。

2) 特點 :異步I/O不會阻塞程式的執行,允許程式在I/O操作進行的同時執行其他任務,提高了程式的並行性和效率。

3) 範例 :在Java中,使用 java.nio.channels.AsynchronousFileChannel 進行檔讀寫就是異步I/O的例子。

阻塞I/O

1) 定義 :阻塞I/O是指程式發起一個I/O操作後,如果數據尚未準備好(如數據未到達、檔未找到等),程式會一直等待,直到數據準備好並完成I/O操作。

2) 特點 :阻塞I/O會導致程式的執行執行緒被掛起,直到I/O操作完成。在這期間,執行緒不能執行其他任務。

3) 範例 :在Java中,使用 java.io 包中的 Socket 進行網路通訊時, InputStream.read() 方法就是阻塞I/O的例子。

非阻塞I/O

1) 定義 :非阻塞I/O是指程式發起一個I/O操作後,如果數據尚未準備好,I/O操作會立即返回一個錯誤或特定值,而不是等待數據準備好。

2) 特點 :非阻塞I/O允許程式在數據未準備好時繼續執行其他任務,而不是等待。程式通常需要輪詢或檢查I/O操作的狀態,以確定何時數據準備好。

3) 範例 :在Java中,使用 java.nio 包中的 SocketChannel 設定為非阻塞模式,並使用 read() 方法進行網路通訊,就是非阻塞I/O的例子。

其他補充

魚聰明 AI 的回答:

魚聰明 AI 地址:https://www.yucongming.com/

  1. 同步IO:當程式發起IO操作時,程式會一直等待IO操作完成後才能繼續執行後續操作,這種IO稱為同步IO。

  2. 異步IO:程式發起IO操作後,不需要等待IO操作完成,而是繼續執行後續操作,當IO操作完成後透過回呼等方式通知程式,這種IO稱為異步IO。

  3. 阻塞IO:程式發起IO操作時,如果IO操作無法立即完成,程式會一直等待IO操作完成或出錯後才能繼續執行後續操作,這種IO稱為阻塞IO。

  4. 非阻塞IO:程式發起IO操作時,如果IO操作無法立即完成,程式會立即返回一個錯誤碼或結果,然後繼續執行後續操作,透過輪詢等方式可以判斷IO操作是否完成,這種IO稱為非阻塞IO。

總結:

  • 同步IO和異步IO是根據程式等待IO操作完成的方式來區分的。

  • 阻塞IO和非阻塞IO是根據程式在等待IO操作完成時是否能繼續執行其他操作來區分的。

  • 歡迎交流

    閱讀完本文,你應該對 IO 三種模型,Java 如何使用 IO 進行讀取,有了一定的了解,本文是面試的重點問題之一,需要重點學習,在文末還有三個問題,歡迎小夥伴在評論區留言!

    1)在實際的編程套用中,你更傾向於使用同步IO還是異步IO?為什麽?

    2)阻塞IO和非阻塞IO在網路編程中有何區別?你在開發網路套用時如何選擇適合的IO模型?

    3)在並行編程中,如何處理IO操作的效能問題?有沒有什麽最佳化策略可以提升IO操作的效率?


    點燃求職熱情!每周持續更新,海量面試題和大廠面經等你挑戰!趕緊關註面試鴨公眾號,輕松備戰春招和暑期實習!

    往期推薦