神秘的数组初始化_I / O神秘化
神秘的數組初始化
由于對高度可擴展的服務器設計的所有炒作以及對Node.js的狂熱,我一直想重點研究IO設計模式,直到現在為止都沒有足夠的時間進行投資。 現在已經做了一些研究,我認為最好記下我遇到的東西,作為對我以及可能遇到這篇文章的任何人的將來參考。 那好吧..讓我們跳上I / O總線去兜風。I / O類型
根據操作的阻塞或非阻塞性質以及IO準備/完成事件通知的同步或異步性質,可以使用四種不同的方法來完成IO。
同步阻塞I / O
IO操作在此阻止應用程序,直到應用程序完成為止,這構成了大多數Web服務器中每個連接模型的典型線程的基礎。
當調用阻塞的read()或write()時,將有一個上下文切換到內核,IO操作將在此發生,并且數據將被復制到內核緩沖區。 之后,內核緩沖區將被轉移到用戶空間應用程序級緩沖區,并且應用程序線程將被標記為可運行
這樣,應用程序將解除阻塞并讀取用戶空間緩沖區中的數據。
每個連接線程模型試圖通過將連接限制在線程中來限制這種阻塞的影響,以使其他并發連接的處理不會被一個連接上的I / O操作阻塞。 只要連接壽命短并且數據鏈接延遲不是那么糟糕,這就很好。 但是在
如果連接壽命長或延遲長,則如果使用固定大小的線程池,線程很可能會長時間被這些連接阻塞,導致新連接餓死,因為阻塞的線程無法在運行中重新用于服務新連接被阻止的狀態,否則
如果使用新線程為每個連接提供服務,將導致在系統內產生大量線程,這可能會占用大量資源,并且對于高并發負載來說,上下文轉換成本很高。
同步非阻塞I / O
在這種模式下,設備或連接被配置為非阻塞,因此不會阻塞read()和write()操作。 這通常意味著如果無法立即滿足該操作,它將返回錯誤代碼,指示該操作將阻塞(POSIX中為EWOULDBLOCK)或設備
暫時不可用(POSIX中為EAGAIN)。 在設備準備就緒并讀取所有數據之前,應由應用程序輪詢。 但是,這不是很有效,因為這些調用中的每一個都會導致上下文切換到內核并返回,而不管是否讀取了某些數據。
具有就緒事件的異步非阻塞I / O
早期模式的問題在于,應用程序必須輪詢并等待完成任務。 當準備好讀取/寫入設備時如何通知應用程序會更好嗎? 這正是此模式為您提供的。 使用特殊的系統調用(因平臺而異–對于Linux為select()/ poll()/ epoll(),對于BSD為kqueue(),對于Solaris為/ dev / poll),應用程序注冊了獲取I / O準備就緒的興趣來自特定設備的特定I / O操作(讀或寫)的信息(Linux術語中是文件描述符,因為所有套接字都是使用文件描述符抽象的)。 此后,將調用此系統調用,該調用將阻塞,直到至少其中一個注冊文件描述符準備就緒為止。 一旦這是真的,準備進行I / O的文件描述符將作為
系統調用的返回,并且可以在應用程序線程中的循環中按順序進行服務。
準備就緒的連接處理邏輯通常包含在用戶提供的事件處理程序中,該事件處理程序仍將必須發出非阻塞的read()/ write()調用以從設備到內核并最終到內核
用戶空間緩沖區,導致上下文切換到內核。 而且,通常沒有絕對的保證可以使用該設備執行預期的I / O,因為操作系統提供的只是該設備可能已準備好執行感興趣的I / O操作的指示。在這種情況下,阻止read()或write()可以使您擺脫困境。 但是,這應該是規范之外的例外。
因此,總體思路是以異步方式獲取就緒事件,并注冊一些事件處理程序以在觸發此類事件通知后進行處理。 因此,您可以看到,所有這些操作都可以在單個線程中完成,同時可以在不同的連接之間進行多路復用,這主要是由于select()的特性(在這里我選擇一個代表性的系統調用),該特性可以一次返回多個套接字的就緒狀態。 這是這種操作模式的吸引力的一部分,在這種操作模式下,一個線程一次可以服務大量連接。 這個
模式通常稱為“非阻止I / O”模型。
Java通過其NIO API提取了特定于平臺的系統調用實現之間的差異。 套接字/文件描述符使用Channels進行抽象,并且Selector封裝選擇系統調用。 對獲取就緒事件感興趣的應用程序向選擇器注冊一個Channel(通常是由ServerSocketChannel上的accept()獲得的SocketChannel),并獲得一個SelectionKey,它用作保存Channel和注冊信息的句柄。 然后在Selector上執行阻塞的select()調用,該調用將返回一組SelectionKey,然后可以對其進行處理
使用應用程序指定的事件處理程序一個接一個地處理。
具有完成事件的異步和非阻塞I / O
就緒事件僅能通知您設備/套接字已準備就緒,請執行某些操作。 應用程序仍然必須進行從設備/套接字到用戶空間緩沖區的數據讀取(更準確地指示操作系統通過系統調用這樣做),直到從設備一直到用戶空間緩沖區。 將作業委派給操作系統在后臺運行,并在完成作業后通過將所有數據從設備傳輸到內核緩沖區,最后傳輸到應用程序級緩沖區,讓它通知您是否很好? 這就是這種模式(通常稱為“異步I / O”模式)背后的基本思想。 為此,需要操作系統支持AIO操作。 在Linux中,此支持在2.6的aio POSIX API中提供,對于Windows,它以“ I / O完成端口”的形式提供。
借助NIO2,Java已通過其AsynchronousChannel API增強了對該模式的支持。
操作系統支持
為了支持就緒和完成事件通知,不同的操作系統提供了不同的系統調用。 對于就緒事件,可以在基于Linux的系統中使用select()和poll()。 但是,較新的epoll()變體是首選的,因為它比select()或poll()更有效率。 select()遭受這樣一個事實,即選擇時間隨所監視的描述符數量線性增加。 覆蓋文件描述符數組引用似乎是臭名昭著的。 因此,每次稱為描述符數組時,都需要從單獨的副本中重新填充它。 無論如何都不是一個優雅的解決方案。
可以通過兩種方式配置epoll()變體。 即邊沿觸發和水平觸發。 在邊緣觸發的情況下,僅當在關聯的描述符上檢測到事件時,它才會發出通知。 在事件觸發的通知中說,您的應用程序處理程序僅讀取內核輸入緩沖區的一半。 現在,即使有一些數據要讀取,它下次也不會在此描述符上得到通知,除非設備準備發送更多數據而導致文件描述符事件。 另一方面,級別觸發的配置將在每次要讀取數據時觸發通知。
根據版本,類似的系統調用以BSD形式的kqueue和/ dev / poll或Solaris中的“ Event Completion”形式出現。 Windows等效為“ I / O完成端口”。
但是,至少在Linux情況下,AIO模式的情況有所不同。 Linux對套接字的aio支持似乎充其量不過是陰暗的,有人暗示它實際上是在內核級別使用就緒事件,而在應用程序級別上對完成事件提供了異步抽象。 但是Windows似乎通過“ I / O完成端口”再次支持了此類。
設計 I / O模式101
在軟件開發中,到處都有模式。 I / O沒什么不同。 與NIO和AIO模型關聯的I / O模式有以下幾種。
React堆模式
有幾個組件參與此模式。 我將首先研究它們,這樣很容易理解該圖。
Reactor Initiator:這是通過配置和啟動調度程序來啟動非阻塞服務器的組件。 首先,它將綁定服務器套接字,并將其注冊到解復用器中,以進行客戶端連接接受就緒事件。 然后,將為調度程序注冊每種就緒事件類型(讀/寫/接受等)的事件處理程序實現。 接下來,調度程序事件循環將被調用以處理事件通知。
調度程序:定義用于注冊,刪除和調度事件處理程序的接口,這些事件處理程序負責對連接事件進行React,這些事件包括連接接受,一組連接上的數據輸入/輸出和超時事件。 為了服務于客戶端連接,相關的事件處理程序(例如:accept事件處理程序)將在解復用器中注冊接受的客戶端通道(用于底層客戶端套接字的包裝器)以及就緒事件的類型,以偵聽該特定通道。 之后,調度程序線程將在多路分解器上為已注冊的通道集調用阻塞準備狀態選擇操作。 一旦為I / O準備好一個或多個注冊通道,調度程序將使用注冊事件處理程序逐一服務與每個就緒通道關聯的每個返回的“句柄”。 這些事件處理程序不要占用調度程序線程,這很重要,因為它將延遲調度程序為其他就緒連接提供服務的時間。 由于事件處理程序中的常規邏輯包括向/從就緒連接傳輸數據/從就緒連接傳輸數據,這將阻塞直到所有數據在用戶空間和內核空間數據緩沖區之間正常傳輸為止,因此,這些處理程序將在與線程不同的線程中運行池。
句柄:一旦通道向解復用器注冊,則該句柄返回,該多路復用器封裝了連接通道和就緒信息。 多路復用器就緒選擇操作將返回一組就緒的句柄。 Java NIO的等效項是SelectionKey。
解復用器:等待一個或多個已注冊連接通道的就緒事件。 Java NIO等效于Selector。
事件處理程序:指定具有鉤子方法的接口,該方法用于調度連接事件。 這些方法需要由特定于應用程序的事件處理程序實現來實現。
具體事件處理程序:包含用于從基礎連接讀取/寫入數據以及執行所需處理或從傳遞的Handle啟動客戶端連接接受協議的邏輯。
事件處理程序通常在線程池的單獨線程中運行,如下圖所示。
此模式的簡單回顯服務器實現如下(沒有事件處理程序線程池)。
public class ReactorInitiator {private static final int NIO_SERVER_PORT = 9993;public void initiateReactiveServer(int port) throws Exception {ServerSocketChannel server = ServerSocketChannel.open();server.socket().bind(new InetSocketAddress(port));server.configureBlocking(false);Dispatcher dispatcher = new Dispatcher();dispatcher.registerChannel(SelectionKey.OP_ACCEPT, server);dispatcher.registerEventHandler(SelectionKey.OP_ACCEPT, new AcceptEventHandler(dispatcher.getDemultiplexer()));dispatcher.registerEventHandler(SelectionKey.OP_READ, new ReadEventHandler(dispatcher.getDemultiplexer()));dispatcher.registerEventHandler(SelectionKey.OP_WRITE, new WriteEventHandler());dispatcher.run(); // Run the dispatcher loop}public static void main(String[] args) throws Exception {System.out.println('Starting NIO server at port : ' +NIO_SERVER_PORT);new ReactorInitiator().initiateReactiveServer(NIO_SERVER_PORT);}}public class Dispatcher {private Map<Integer, EventHandler> registeredHandlers =new ConcurrentHashMap<Integer, EventHandler>();private Selector demultiplexer;public Dispatcher() throws Exception {demultiplexer = Selector.open();}public Selector getDemultiplexer() {return demultiplexer;}public void registerEventHandler(int eventType, EventHandler eventHandler) {registeredHandlers.put(eventType, eventHandler);}// Used to register ServerSocketChannel with the// selector to accept incoming client connectionspublic void registerChannel(int eventType, SelectableChannel channel) throws Exception {channel.register(demultiplexer, eventType);}public void run() {try {while (true) { // Loop indefinitelydemultiplexer.select();Set<SelectionKey> readyHandles =demultiplexer.selectedKeys();Iterator<SelectionKey> handleIterator =readyHandles.iterator();while (handleIterator.hasNext()) {SelectionKey handle = handleIterator.next();if (handle.isAcceptable()) {EventHandler handler =registeredHandlers.get(SelectionKey.OP_ACCEPT);handler.handleEvent(handle);// Note : Here we don't remove this handle from// selector since we want to keep listening to// new client connections}if (handle.isReadable()) {EventHandler handler =registeredHandlers.get(SelectionKey.OP_READ);handler.handleEvent(handle);handleIterator.remove();}if (handle.isWritable()) {EventHandler handler =registeredHandlers.get(SelectionKey.OP_WRITE);handler.handleEvent(handle);handleIterator.remove();}}}} catch (Exception e) {e.printStackTrace();}}}public interface EventHandler {public void handleEvent(SelectionKey handle) throws Exception;}public class AcceptEventHandler implements EventHandler {private Selector demultiplexer;public AcceptEventHandler(Selector demultiplexer) {this.demultiplexer = demultiplexer;}@Overridepublic void handleEvent(SelectionKey handle) throws Exception {ServerSocketChannel serverSocketChannel =(ServerSocketChannel) handle.channel();SocketChannel socketChannel = serverSocketChannel.accept();if (socketChannel != null) {socketChannel.configureBlocking(false);socketChannel.register(demultiplexer, SelectionKey.OP_READ);}}}public class ReadEventHandler implements EventHandler {private Selector demultiplexer;private ByteBuffer inputBuffer = ByteBuffer.allocate(2048);public ReadEventHandler(Selector demultiplexer) {this.demultiplexer = demultiplexer;}@Overridepublic void handleEvent(SelectionKey handle) throws Exception {SocketChannel socketChannel =(SocketChannel) handle.channel();socketChannel.read(inputBuffer); // Read data from clientinputBuffer.flip();// Rewind the buffer to start reading from the beginningbyte[] buffer = new byte[inputBuffer.limit()];inputBuffer.get(buffer);System.out.println('Received message from client : ' +new String(buffer));inputBuffer.flip();// Rewind the buffer to start reading from the beginning// Register the interest for writable readiness event for// this channel in order to echo back the messagesocketChannel.register(demultiplexer, SelectionKey.OP_WRITE, inputBuffer);}}public class WriteEventHandler implements EventHandler {@Overridepublic void handleEvent(SelectionKey handle) throws Exception {SocketChannel socketChannel =(SocketChannel) handle.channel();ByteBuffer inputBuffer = (ByteBuffer) handle.attachment();socketChannel.write(inputBuffer);socketChannel.close(); // Close connection}}前攝者模式
該模式基于異步I / O模型。 主要組成部分如下。
主動啟動器:這是啟動異步操作以接受客戶端連接的實體。 這通常是服務器應用程序的主線程。 將完成處理程序與完成調度程序一起注冊以處理連接接受異步事件通知。
異步操作處理器:負責異步執行I / O操作,并向應用程序級別完成處理程序提供完成事件通知。 這通常是操作系統公開的異步I / O接口。
異步操作:異步操作由異步操作處理器在單獨的內核線程中運行以完成操作。
完成分配器:負責異步操作完成時回調到應用程序完成處理程序。 當異步操作處理器完成異步啟動的操作時,完成調度程序將代表它執行應用程序回調。 通常,根據事件的類型將事件通知處理委托給適當的完成處理程序。
完成處理程序:這是應用程序實現的接口,用于處理異步事件完成事件。
讓我們看看如何使用Java 7中添加的新Java NIO.2 API來實現此模式(作為簡單的回顯服務器)。
public class ProactorInitiator {static int ASYNC_SERVER_PORT = 4333;public void initiateProactiveServer(int port)throws IOException {final AsynchronousServerSocketChannel listener =AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(port));AcceptCompletionHandler acceptCompletionHandler =new AcceptCompletionHandler(listener);SessionState state = new SessionState();listener.accept(state, acceptCompletionHandler);}public static void main(String[] args) {try {System.out.println('Async server listening on port : ' +ASYNC_SERVER_PORT);new ProactorInitiator().initiateProactiveServer(ASYNC_SERVER_PORT);} catch (IOException e) {e.printStackTrace();}// Sleep indefinitely since otherwise the JVM would terminatewhile (true) {try {Thread.sleep(Long.MAX_VALUE);} catch (InterruptedException e) {e.printStackTrace();}}} }public class AcceptCompletionHandlerimplementsCompletionHandler<AsynchronousSocketChannel, SessionState> {private AsynchronousServerSocketChannel listener;public AcceptCompletionHandler(AsynchronousServerSocketChannel listener) {this.listener = listener;}@Overridepublic void completed(AsynchronousSocketChannel socketChannel,SessionState sessionState) {// accept the next connectionSessionState newSessionState = new SessionState();listener.accept(newSessionState, this);// handle this connectionByteBuffer inputBuffer = ByteBuffer.allocate(2048);ReadCompletionHandler readCompletionHandler =new ReadCompletionHandler(socketChannel, inputBuffer);socketChannel.read(inputBuffer, sessionState, readCompletionHandler);}@Overridepublic void failed(Throwable exc, SessionState sessionState) {// Handle connection failure...}}public class ReadCompletionHandler implementsCompletionHandler<Integer, SessionState> {private AsynchronousSocketChannel socketChannel;private ByteBuffer inputBuffer;public ReadCompletionHandler(AsynchronousSocketChannel socketChannel,ByteBuffer inputBuffer) {this.socketChannel = socketChannel;this.inputBuffer = inputBuffer;}@Overridepublic void completed(Integer bytesRead, SessionState sessionState) {byte[] buffer = new byte[bytesRead];inputBuffer.rewind();// Rewind the input buffer to read from the beginninginputBuffer.get(buffer);String message = new String(buffer);System.out.println('Received message from client : ' +message);// Echo the message back to clientWriteCompletionHandler writeCompletionHandler =new WriteCompletionHandler(socketChannel);ByteBuffer outputBuffer = ByteBuffer.wrap(buffer);socketChannel.write(outputBuffer, sessionState, writeCompletionHandler);}@Overridepublic void failed(Throwable exc, SessionState attachment) {//Handle read failure.....}}public class WriteCompletionHandler implementsCompletionHandler<Integer, SessionState> {private AsynchronousSocketChannel socketChannel;public WriteCompletionHandler(AsynchronousSocketChannel socketChannel) {this.socketChannel = socketChannel;}@Overridepublic void completed(Integer bytesWritten, SessionState attachment) {try {socketChannel.close();} catch (IOException e) {e.printStackTrace();}}@Overridepublic void failed(Throwable exc, SessionState attachment) {// Handle write failure.....}}public class SessionState {private Map<String, String> sessionProps =new ConcurrentHashMap<String, String>();public String getProperty(String key) {return sessionProps.get(key);}public void setProperty(String key, String value) {sessionProps.put(key, value);}} 每種類型的事件完成(接受/讀取/寫入)由實現CompletionHandler接口(接受/讀取/ WriteCompletionHandler等)的單獨的完成處理程序處理。 在這些連接處理程序中管理狀態轉換。 附加的SessionState參數可用于
在一系列完成事件中保持客戶端會話的特定狀態。
NIO框架(HTTPCore)
如果您正在考慮實現基于NIO的HTTP服務器,那么您很幸運。 Apache HTTPCore庫為使用NIO處理HTTP流量提供了出色的支持。 API通過內置的HTTP請求處理功能,在NIO層之上提供了更高級別的抽象。下面給出了一個最小的非阻塞HTTP服務器實現,該實現為任何GET請求返回一個虛擬輸出。
public class NHttpServer {public void start() throws IOReactorException {HttpParams params = new BasicHttpParams();// Connection parametersparams.setIntParameter(HttpConnectionParams.SO_TIMEOUT, 60000).setIntParameter(HttpConnectionParams.SOCKET_BUFFER_SIZE, 8 * 1024).setBooleanParameter(HttpConnectionParams.STALE_CONNECTION_CHECK, true).setBooleanParameter(HttpConnectionParams.TCP_NODELAY, true);final DefaultListeningIOReactor ioReactor =new DefaultListeningIOReactor(2, params);// Spawns an IOReactor having two reactor threads// running selectors. Number of threads here is// usually matched to the number of processor cores// in the system// Application specific readiness event handlerServerHandler handler = new ServerHandler();final IOEventDispatch ioEventDispatch =new DefaultServerIOEventDispatch(handler, params);// Default IO event dispatcher encapsulating the// event handlerListenerEndpoint endpoint = ioReactor.listen(new InetSocketAddress(4444));// start the IO reactor in a new separate threadThread t = new Thread(new Runnable() {public void run() {try {System.out.println('Listening in port 4444');ioReactor.execute(ioEventDispatch);} catch (InterruptedIOException ex) {ex.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (Exception e) {e.printStackTrace();}}});t.start();// Wait for the endpoint to become ready,// i.e. for the listener to start accepting requests.try {endpoint.waitFor();} catch (InterruptedException e) {e.printStackTrace();}}public static void main(String[] args)throws IOReactorException {new NHttpServer().start();}}public class ServerHandler implements NHttpServiceHandler {private static final int BUFFER_SIZE = 2048;private static final String RESPONSE_SOURCE_BUFFER ='response-source-buffer';// the factory to create HTTP responsesprivate final HttpResponseFactory responseFactory;// the HTTP response processorprivate final HttpProcessor httpProcessor;// the strategy to re-use connectionsprivate final ConnectionReuseStrategy connStrategy;// the buffer allocatorprivate final ByteBufferAllocator allocator;public ServerHandler() {super();this.responseFactory = new DefaultHttpResponseFactory();this.httpProcessor = new BasicHttpProcessor();this.connStrategy = new DefaultConnectionReuseStrategy();this.allocator = new HeapByteBufferAllocator();}@Overridepublic void connected(NHttpServerConnection nHttpServerConnection) {System.out.println('New incoming connection');}@Overridepublic void requestReceived(NHttpServerConnection nHttpServerConnection) {HttpRequest request =nHttpServerConnection.getHttpRequest();if (request instanceof HttpEntityEnclosingRequest) {// Handle POST and PUT requests} else {ContentOutputBuffer outputBuffer =new SharedOutputBuffer(BUFFER_SIZE, nHttpServerConnection, allocator);HttpContext context =nHttpServerConnection.getContext();context.setAttribute(RESPONSE_SOURCE_BUFFER, outputBuffer);OutputStream os =new ContentOutputStream(outputBuffer);// create the default response to this requestProtocolVersion httpVersion =request.getRequestLine().getProtocolVersion();HttpResponse response =responseFactory.newHttpResponse(httpVersion, HttpStatus.SC_OK,nHttpServerConnection.getContext());// create a basic HttpEntity using the source// channel of the response pipeBasicHttpEntity entity = new BasicHttpEntity();if (httpVersion.greaterEquals(HttpVersion.HTTP_1_1)) {entity.setChunked(true);}response.setEntity(entity);String method = request.getRequestLine().getMethod().toUpperCase();if (method.equals('GET')) {try {nHttpServerConnection.suspendInput();nHttpServerConnection.submitResponse(response);os.write(new String('Hello client..').getBytes('UTF-8'));os.flush();os.close();} catch (Exception e) {e.printStackTrace();}} // Handle other http methods}}@Overridepublic void inputReady(NHttpServerConnection nHttpServerConnection,ContentDecoder contentDecoder) {// Handle request enclosed entities here by reading// them from the channel}@Overridepublic void responseReady(NHttpServerConnection nHttpServerConnection) {try {nHttpServerConnection.close();} catch (IOException e) {e.printStackTrace();}}@Overridepublic void outputReady(NHttpServerConnection nHttpServerConnection,ContentEncoder encoder) {HttpContext context = nHttpServerConnection.getContext();ContentOutputBuffer outBuf =(ContentOutputBuffer) context.getAttribute(RESPONSE_SOURCE_BUFFER);try {outBuf.produceContent(encoder);} catch (IOException e) {e.printStackTrace();}}@Overridepublic void exception(NHttpServerConnection nHttpServerConnection,IOException e) {e.printStackTrace();}@Overridepublic void exception(NHttpServerConnection nHttpServerConnection,HttpException e) {e.printStackTrace();}@Overridepublic void timeout(NHttpServerConnection nHttpServerConnection) {try {nHttpServerConnection.close();} catch (IOException e) {e.printStackTrace();}}@Overridepublic void closed(NHttpServerConnection nHttpServerConnection) {try {nHttpServerConnection.close();} catch (IOException e) {e.printStackTrace();}}}IOReactor類基本上將使用處理預備事件的ServerHandler實現包裝解復用器功能。
Apache Synapse(開源ESB)包含基于NIO的HTTP服務器的良好實現,其中NIO用于為每個實例擴展大量客戶端,并且隨著時間的推移內存使用量相當穩定。 該實現還包含與Axis2傳輸框架集成一起內置的良好調試和服務器統計信息收集機制。 可以在[1]中找到。
結論
在進行I / O時,有多種選擇會影響服務器的可伸縮性和性能。 上面的每種I / O機制各有利弊,因此應根據預期的可伸縮性和性能特征以及這些方法的易維護性來做出決定。 這結束了我關于I / O的漫長文章。 隨時提供您可能有的建議,更正或評論。 可以從此處下載文章中概述的服務器的完整源代碼以及客戶端。
相關鏈接
我在此過程中經歷了許多參考。 以下是一些有趣的內容。
[1] http://www.ibm.com/developerworks/java/library/j-nio2-1/index.html [2] http://www.ibm.com/developerworks/linux/library/l-async / [3] http://lse.sourceforge.net/io/aionotes.txt [4] http://wknight8111.blogspot.com/?tag=aio [5] http://nick-black.com/dankwiki /index.php/Fast_UNIX_Servers [6] http://today.java.net/pub/a/today/2007/02/13/architecture-of-highly-scalable-nio-server.html [7] Java NIO ,作者:羅恩希欽斯[8] http://www.dre.vanderbilt.edu/~schmidt/PDF/reactor-siemens.pdf [9] http://www.cs.wustl.edu/~schmidt/PDF/proactor.pdf [10] http://www.kegel.com/c10k.html參考: I / O來自Source Open博客,由我們的JCG合作伙伴 Buddhika Chamith揭秘。
翻譯自: https://www.javacodegeeks.com/2012/08/io-demystified.html
神秘的數組初始化
總結
以上是生活随笔為你收集整理的神秘的数组初始化_I / O神秘化的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 宇文邕最爱的女人是谁(独孤天下宇文邕有几
- 下一篇: 按键精灵怎么设置循环(按键精灵怎么设置循