跳至主要内容

Java IO (4): AIO

Java IO (4): AIO

Before we continue to dive into the concepts and design of AIO (asynchronous IO), we need to make the differences between NIO (non-blocking IO) and AIO, from the kernel perspective.

Difference Between Blocking and Synchronous

We have already heard the phrase like Blocking IO and Synchronous IO, but what the differences here?

In order to understand it, we need to see that when we do a IO operation, it generally has two phases:

  • Our user process submit the IO operation to OS kernel, i.e. call a System Call of OS: If our user process is blocked when submitting IO job to OS kernel, we call it as Blocking IO. If it is not blocked, on the other hand, we call it Non-blocking IO.
  • The OS kernel coordinate many kernel process, like Disk Driver & File System, to do the real IO operation: If our process still waiting when OS doing real IO operation, we call it Synchronous IO. Otherwise, it is called Asynchronous IO.

So we can see how Java IO model evolved:

Blocking IO: stream & reader
=>
Blocking Synchronous multiplex IO: selector & channel & buffer
# Even the `select` has time out mechanism, it is still blokcing.
# So, the term `NIO` may better be seen as `New IO`, but not Non-blocking IO
=>
Non-Blocking Aynchronous IO: aynchronous channel & callback

And here is a question with illustration describes the differences.

Async IO

In Async IO, we still have Channel and Buffer, but the AsynchronousChannel has different interfaces comparing with normal Channel. It can receive a CompletionHandler, which is the callback method when IO operation is done.

<A> void read(ByteBuffer dst,  
              A attachment,  
              CompletionHandler<Integer,? super A> handler);

<A> void write(ByteBuffer src,  
               A attachment,  
               CompletionHandler<Integer,? super A> handler);

Also, Java provides similar interfaces to make it Synchronous:

Future<Integer> read(ByteBuffer dst);

CompletionHandler and Callback

This interface is very readable, and the attachment is Buffer in most of times. When the IO operation is done, the completed method will be called and failed will be invoked when some exception happens.

public interface CompletionHandler<V,A> {  
  
   void completed(V result, A attachment);  
  
   void failed(Throwable exc, A attachment);  
}

Thread Pools

As the CompletionHandler is called in asynchronous way, we need to find a thread to run the code in it. If we use the thread submitted the IO job, this thread may be interrupted frequently and normal process maybe influenced. So, Java decided to add an thread pools to do it in background threads (if we doesn’t provide one, Java will provide ).

What should be noticed is two points related about the usage of thread pool:

  • The completion handler should never be blocking indefinitely, otherwise worker in thread pool will be drained. In other word, the task in completion handler should be fast and short;
  • The thread pool must support unbounded queueing.

For more information, refer to openjdk: notes on aio implementation.

Ref

Written with StackEdit.

评论

此博客中的热门博文

Spring Boot: Customize Environment

Spring Boot: Customize Environment Environment variable is a very commonly used feature in daily programming: used in init script used in startup configuration used by logging etc In Spring Boot, all environment variables are a part of properties in Spring context and managed by Environment abstraction. Because Spring Boot can handle the parse of configuration files, when we want to implement a project which uses yml file as a separate config file, we choose the Spring Boot. The following is the problems we met when we implementing the parse of yml file and it is recorded for future reader. Bind to Class Property values can be injected directly into your beans using the @Value annotation, accessed via Spring’s Environment abstraction or bound to structured objects via @ConfigurationProperties. As the document says, there exists three ways to access properties in *.properties or *.yml : @Value : access single value Environment : can access multi

Elasticsearch: Join and SubQuery

Elasticsearch: Join and SubQuery Tony was bothered by the recent change of search engine requirement: they want the functionality of SQL-like join in Elasticsearch! “They are crazy! How can they think like that. Didn’t they understand that Elasticsearch is kind-of NoSQL 1 in which every index should be independent and self-contained? In this way, every index can work independently and scale as they like without considering other indexes, so the performance can boost. Following this design principle, Elasticsearch has little related supports.” Tony thought, after listening their requirements. Leader notice tony’s unwillingness and said, “Maybe it is hard to do, but the requirement is reasonable. We need to search person by his friends, didn’t we? What’s more, the harder to implement, the more you can learn from it, right?” Tony thought leader’s word does make sense so he set out to do the related implementations Application-Side Join “The first implementation

Implement isdigit

It is seems very easy to implement c library function isdigit , but for a library code, performance is very important. So we will try to implement it and make it faster. Function So, first we make it right. int isdigit ( char c) { return c >= '0' && c <= '9' ; } Improvements One – Macro When it comes to performance for c code, macro can always be tried. #define isdigit (c) c >= '0' && c <= '9' Two – Table Upper version use two comparison and one logical operation, but we can do better with more space: # define isdigit(c) table[c] This works and faster, but somewhat wasteful. We need only one bit to represent true or false, but we use a int. So what to do? There are many similar functions like isalpha(), isupper ... in c header file, so we can combine them into one int and get result by table[c]&SOME_BIT , which is what source do. Source code of ctype.h : # define _ISbit(bit) (1 << (