Java NIO.2异步通道编码指南

Java NIO.2异步通道编码指南,java,scala,asynchronous,nio2,Java,Scala,Asynchronous,Nio2,例如,我想向数组读取100500字节: byte[] array = new byte[100500]; int offset = 0; ByteBuffer buf = ByteBuffer.directBuffer(4096); channel.read(buffer, null, new LambdaAdapter((count, exception, attachment) -> { buf.get(array, offset, count); offset +=

例如,我想向数组读取100500字节:

byte[] array = new byte[100500];
int offset = 0;
ByteBuffer buf = ByteBuffer.directBuffer(4096);

channel.read(buffer, null, new LambdaAdapter((count, exception, attachment) -> {
    buf.get(array, offset, count);
    offset += count; //will not work, offset must be final
    if (offset < 100500) {
        channel.read(buffer, null, /*what here? must be lambda we are currently in but we can't use it!*/)
    }
    //here we have our 100500 bytes inside array
});
byte[]数组=新字节[100500];
整数偏移=0;
ByteBuffer buf=ByteBuffer.directBuffer(4096);
读取(缓冲区,空,新LambdaAdapter((计数,异常,附件)->{
获取(数组、偏移量、计数);
偏移量+=count;//不起作用,偏移量必须是最终值
如果(偏移量<100500){
channel.read(buffer,null,/*这里是什么?必须是我们当前所在的lambda,但我们无法使用它!*/)
}
//这里我们有100500字节的数组
});
LambdaAdapter是一个简单的包装器,它将CompletionHandler转换为带有三个参数的函数接口

无论如何。偏移量可以放在“attachment”参数中,lambda可以预先声明并作为字段重用。然而,生成的代码总是难看的

即使对于这样简单的任务,我也无法编写可接受的解决方案——读与写交错并封装在复杂逻辑中的复杂协议会是什么样子


有人知道处理异步API的合适方法吗?如果你认为Scala可以拯救世界,请随意使用。

我知道如何处理异步计算IO,特别是异步IO。异步程序应该表示为数据流图,如中所述。每个节点都有一组输入,每个输入都接受消息或信号,并激发(转到线程池)当所有输入都已填充时。例如,表示套接字通道的节点有两个输入:一个用于ByteBuffers,另一个用于指示通道是空闲的并且可以接受IO请求。因此,节点类似于函数式编程中的函数,但可以重用-不会为下一个IO操作创建新对象

Scala(和Akka)演员不适合,因为每个演员只有一个输入


我已经为java开发了一个数据流库,但它有点过时(我正在考虑更优雅,或者至少不那么难看的API)。查看examples子目录中的echo服务器实现。

我找到了可接受的解决方案。 首先,以下几点值得一看:

至于编码准则

  • Async方法是在执行任何有用的工作之前返回的方法
  • 异步操作代码应该从创建新对象开始,我们称之为上下文

    Void startMyAsync(String p1, int p2, Observer callback) {
         return new MyAsyncContext(p1, p2, callback).start();
    }
    
  • 未使用异步操作方法的结果-让我们返回Void类型。这很有用,因为编译器将为您检查每个异步方法是否调用另一个异步方法或显式返回null

  • 异步方法可以引发异常
  • 异步回调不应引发异常-必须使用回调错误处理程序
  • 异步回调应该只包含try…catch和上下文方法调用
  • 异步回调也应该返回Void
  • 不需要CompletionHandler提供的其他数据-应使用上下文字段。如果异步流未拆分,则不需要同步
异步回调的示例:

return myAsyncMethod(param1, param2, (result, exc, att) -> {
    try {
        if (exc != null) {
            return handleError(exc); //cleanup resources and invoke parentHandler.complete(null, exc, null)
        } else {
            return handleResult(result);
        }
    } catch (Exception e) {
        return handleError(exc); //cleanup resources and invoke parentHandler.complete(null, exc, null)
    }
});

Scala可能在非最终偏移量上关闭。至于
channel.read
的第二次调用,您是否可以使用
this
获取对
lambdadapter
的引用?将偏移量设置为字段,而不是局部变量。