问题描述
虽然异步IO(无阻塞描述选择/投票/ epoll的/ kqueue的等)不在网络上最记载的东西,也有很好的例子屈指可数。
Whilst asynchronous IO (non-blocking descriptors with select/poll/epoll/kqueue etc) is not the most documented thing on the web, there are a handful of good examples.
然而,所有这些例子中,已经确定由该调用返回的句柄,只是有一个 do_some_io(FD)
存根。它们并不真正解释如何最好接近实际的异步IO在这样的方法
However, all these examples, having determined the handles that are returned by the call, just have a 'do_some_io(fd)
' stub. They don't really explain how to best approach the actual asynchronous IO in such a method.
阻塞IO很整洁,简单的阅读code。非阻塞,异步IO是,在另一方面,有毛和杂乱。
Blocking IO is very tidy and straightforward to read code. Non-blocking, async IO is, on the other hand, hairy and messy.
有什么办法呢?什么是稳健和可读性?
What approaches are there? What are robust and readable?
void do_some_io(int fd) {
switch(state) {
case STEP1:
... async calls
if(io_would_block)
return;
state = STEP2;
case STEP2:
... more async calls
if(io_would_block)
return;
state = STEP3;
case STEP3:
...
}
}
或者(AB)使用GCC的计算转移:
or perhaps (ab)using GCC's computed gotos:
#define concatentate(x,y) x##y
#define async_read_xx(var,bytes,line) \
concatentate(jmp,line): \
if(!do_async_read(bytes,&var)) { \
schedule(EPOLLIN); \
jmp_read = &&concatentate(jmp,line); \
return; \
}
// macros for making async code read like sync code
#define async_read(var,bytes) \
async_read_xx(var,bytes,__LINE__)
#define async_resume() \
if(jmp_read) { \
void* target = jmp_read; \
jmp_read = NULL; \
goto *target; \
}
void do_some_io() {
async_resume();
async_read(something,sizeof(something));
async_read(something_else,sizeof(something_else));
}
或许C ++异常和状态机,所以工人功能可以触发中止/恢复位,或者表驱动的状态机?
Or perhaps C++ exceptions and a state machine, so worker functions can trigger the abort/resume bit, or perhaps a table-driven state-machine?
它不是如何使它工作,它如何使维护了我追逐!
Its not how to make it work, its how to make it maintainable that I'm chasing!
推荐答案
我建议采取一看:,第二次取像libevent的,现有的库看看Boost.Asio的已经做的工作,看看他们是如何工作的。
I suggest take a look on: http://www.kegel.com/c10k.html, second take a look on existing libraries like libevent, Boost.Asio that already do the job and see how they work.
的一点是,该方法可以是对每种类型的系统调用的不同:
The point is that the approach may be different for each type of system call:
- 选择简单反应堆
- epoll的既有边沿或电平触发,需要不同的方法接口
- IOCP是摄需要其他的方法
建议:用好现有的库象Boost.Asio的为C ++或libevent的对C
Suggestion: use good existing library like Boost.Asio for C++ or libevent for C.
编辑:这是ASIO如何处理这种
This is how ASIO handles this
class connection {
boost::asio:ip::tcp::socket socket_;
public:
void run()
{
// for variable length chunks
async_read_until(socket_,resizable_buffer,'\n',
boost::bind(&run::on_line_recieved,this,errorplacehplder);
// or constant length chunks
async_read(socket_,buffer(some_buf,buf_size),
boost::bind(&run::on_line_recieved,this,errorplacehplder);
}
void on_line_recieved(error e)
{
// handle it
run();
}
};
由于ASIO的工作原理摄通知您,当操作完成,
处理EWOULDBLOCK内部。
Because ASIO works as proactor it notifies you when operation is complete andhandles EWOULDBLOCK internally.
如果你作为反应堆字,你可以模仿这种行为:
If you word as reactor you may simulate this behavior:
class conn {
// Application logic
void run() {
read_chunk(&conn::on_chunk_read,size);
}
void on_chunk_read() {
/* do something;*/
}
// Proactor wrappers
void read_chunk(void (conn::*callback),int size, int start_point=0) {
read(socket,buffer+start,size)
if( complete )
(this->*callback()
else {
this -> tmp_size-=size-read;
this -> tmp_start=start+read;
this -> tmp_callback=callback
your_event_library_register_op_on_readable(callback,socket,this);
}
}
void callback()
{
read_chunk(tmp_callback,tmp_size,tmp_start);
}
}
类似的东西。
这篇关于整洁code为异步IO的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!