Я использую библиотеку Netty (версия 4 от GitHub). Он отлично работает в Scala, но я надеюсь, что моя библиотека сможет использовать стиль передачи продолжения для асинхронного ожидания.
Традиционно с Netty вы должны сделать что-то вроде этого (пример операции асинхронного подключения):
//client is a ClientBootstrap
val future:ChannelFuture = client.connect(remoteAddr);
future.addListener(new ChannelFutureListener {
def operationComplete (f:ChannelFuture) = {
//here goes the code that happens when the connection is made
}
})
Если вы реализуете библиотеку (каковой я являюсь), то у вас в основном есть три простых варианта, позволяющих пользователю библиотеки выполнять какие-либо действия после установления соединения:
- Просто верните ChannelFuture из вашего метода подключения и позвольте пользователю разобраться с ним - это не обеспечивает большой абстракции от netty.
- Возьмите ChannelFutureListener в качестве параметра вашего метода подключения и добавьте его в качестве слушателя в ChannelFuture.
- Возьмите объект функции обратного вызова в качестве параметра вашего метода подключения и вызовите его из созданного вами ChannelFutureListener (это сделало бы стиль, управляемый обратным вызовом, чем-то вроде node.js).
Я пытаюсь сделать четвертый вариант; Я не включил его в счет выше, потому что это непросто.
Я хочу использовать продолжения с разделителями scala, чтобы использование библиотеки было чем-то вроде библиотеки блокировки, но за кулисами она не будет блокироваться:
class MyLibraryClient {
def connect(remoteAddr:SocketAddress) = {
shift { retrn: (Unit => Unit) => {
val future:ChannelFuture = client.connect(remoteAddr);
future.addListener(new ChannelFutureListener {
def operationComplete(f:ChannelFuture) = {
retrn();
}
});
}
}
}
}
Представьте, что другие операции чтения / записи реализуются таким же образом. Цель этого состоит в том, чтобы код пользователя мог выглядеть примерно так:
reset {
val conn = new MyLibraryClient();
conn.connect(new InetSocketAddress("127.0.0.1", 1337));
println("This will happen after the connection is finished");
}
Другими словами, программа будет выглядеть как простая программа в стиле блокировки, но за кулисами не будет никакой блокировки или потоковой передачи.
Проблема, с которой я сталкиваюсь, заключается в том, что я не совсем понимаю, как работает типизация разделенных продолжений. Когда я пытаюсь реализовать это описанным выше способом, компилятор жалуется, что моя реализация operationComplete
фактически возвращает Unit @scala.util.continuations.cpsParam[Unit,Unit => Unit]
вместо Unit
. Я понимаю, что в scala CPS есть своего рода "ошибка" в том, что вы должны аннотировать возвращаемый тип метода shift
с помощью @suspendable
, который передается вверх по стеку вызовов до reset
, но, похоже, нет никакого способа согласовать это с уже существующей библиотекой Java, которая не имеет концепции разграниченных продолжений.
Я чувствую, что действительно должен быть способ обойти это - если Swarm может сериализовать продолжения и заглушить их по сети для вычисления в другом месте, тогда должна быть возможность просто вызвать продолжение из уже существующего класса Java. Но я не могу понять, как это можно сделать. Придется ли мне полностью переписать netty на Scala, чтобы это произошло?
reset
, и, таким образом, поймет, что вызовы не блокируются. На самом деле это всего лишь способ: A) получить более глубокое понимание продолжений с разделителями и B) поэкспериментировать с написанием кода, основанного на обратном вызове, более чистым способом. - person Jeremy   schedule 08.02.2012