zagursky
TRANSCRIPT
![Page 1: Zagursky](https://reader034.vdocuments.net/reader034/viewer/2022052412/5587899fd8b42a4c318b4667/html5/thumbnails/1.jpg)
![Page 2: Zagursky](https://reader034.vdocuments.net/reader034/viewer/2022052412/5587899fd8b42a4c318b4667/html5/thumbnails/2.jpg)
Файберы
Невытесняющая многозадачность на Java
![Page 3: Zagursky](https://reader034.vdocuments.net/reader034/viewer/2022052412/5587899fd8b42a4c318b4667/html5/thumbnails/3.jpg)
S R
MsgRequest
MsgResponse
ResponseHandler()
RequestHandler()
public final class RequestCreateAvatar { private final String avatarName; private final Character character; }
public final class CreateAvatarHandler { public void handle(RequestCreateAvatar msg) { CreateAvatarResult result = avatarManager.createAvatar(msg); sendMsg(new ResponseCreateAvatar(result)); } }
void createAvatar(String avatarName, Character character) { sendCmd(new RequestCreateAvatar(avatarName, character)); }
public final class CreateAvatarResponseHandler { public void handle(ResponseCreateAvatar msg) { sendMsgToClient(msg); } }
Async<Void> createAvatar(String avatarName, Character character) { CreateAvatarResult result = call(avatarManager.createAvatar( avatarName, character )); sendMsgToClient(result); return nothing(); }
![Page 4: Zagursky](https://reader034.vdocuments.net/reader034/viewer/2022052412/5587899fd8b42a4c318b4667/html5/thumbnails/4.jpg)
![Page 5: Zagursky](https://reader034.vdocuments.net/reader034/viewer/2022052412/5587899fd8b42a4c318b4667/html5/thumbnails/5.jpg)
Причины • Хочется писать простой линейный Java-код
• ОС-потоки слишком накладны
• Требуется сохранить однопоточный дизайн
![Page 6: Zagursky](https://reader034.vdocuments.net/reader034/viewer/2022052412/5587899fd8b42a4c318b4667/html5/thumbnails/6.jpg)
С высоты птичьего полёта
Инструментатор Планировщик
Инспекции Рантайм
![Page 7: Zagursky](https://reader034.vdocuments.net/reader034/viewer/2022052412/5587899fd8b42a4c318b4667/html5/thumbnails/7.jpg)
import fibers.Async; import static fibers.Fiber.*; class Foo { Async<Integer> calcResult(int factor) { return result(42*factor); } Async<Integer> doWork() { int tmp = call(calcResult(314)); return result(tmp); } }
Синтаксис (1)
Async<Integer> calcResult(int factor) {
return result(42*factor);
}
Async<Integer> doWork() {
int tmp = сall(calcResult(314));
return result(tmp);
}
![Page 8: Zagursky](https://reader034.vdocuments.net/reader034/viewer/2022052412/5587899fd8b42a4c318b4667/html5/thumbnails/8.jpg)
Синтаксис (2) class Foo {
void bar(FiberManager f) {
f.scheduleFiber(doWork("Hi!"));
}
}
![Page 9: Zagursky](https://reader034.vdocuments.net/reader034/viewer/2022052412/5587899fd8b42a4c318b4667/html5/thumbnails/9.jpg)
Препарируемый метод
Async<String> baz(String second) {
String first = call(getFirst());
return result(join(first, second));
}
![Page 10: Zagursky](https://reader034.vdocuments.net/reader034/viewer/2022052412/5587899fd8b42a4c318b4667/html5/thumbnails/10.jpg)
Замена исходного метода
Async<String> baz(String second) {
return new baz_Context(second);
}
![Page 11: Zagursky](https://reader034.vdocuments.net/reader034/viewer/2022052412/5587899fd8b42a4c318b4667/html5/thumbnails/11.jpg)
Контекст вызова метода
class baz_Context extends Async<String> {
String _second, first;
@Override
void update() { state = baz_Async(this); }
}
![Page 12: Zagursky](https://reader034.vdocuments.net/reader034/viewer/2022052412/5587899fd8b42a4c318b4667/html5/thumbnails/12.jpg)
Инструментированный метод int baz_Async(baz_Context c) {
switch (c.state) {
case 0: c.result = getFirst(); return 1;
case 1: c.first = (String) c.takeResult();
c.result = join(c.first, c._second);
return -1;
}
}
![Page 13: Zagursky](https://reader034.vdocuments.net/reader034/viewer/2022052412/5587899fd8b42a4c318b4667/html5/thumbnails/13.jpg)
Инструментирование (1) • Поиск точек разрыва
– call
– yield
• Вставка switch-case и return
![Page 14: Zagursky](https://reader034.vdocuments.net/reader034/viewer/2022052412/5587899fd8b42a4c318b4667/html5/thumbnails/14.jpg)
Инструментирование (2) • Как обойти вызов
блока finally?
• Не вызывать его!
Async<Integer> foo() {
try {
int t = call(bar());
return result(t);
} finally { close(); }
}
![Page 15: Zagursky](https://reader034.vdocuments.net/reader034/viewer/2022052412/5587899fd8b42a4c318b4667/html5/thumbnails/15.jpg)
Инструментирование (3) • Подмена доступа к параметрам метода и
локальным переменным
• int x; x = 42; context.x = 42;
![Page 16: Zagursky](https://reader034.vdocuments.net/reader034/viewer/2022052412/5587899fd8b42a4c318b4667/html5/thumbnails/16.jpg)
Инструментирование (4)
... x = call(bar()); ...
... case 42 Context r = new bar_Context(); c.pushCall(r); return 43; case 43: c.x = (String) c.takeResult(); ...
![Page 17: Zagursky](https://reader034.vdocuments.net/reader034/viewer/2022052412/5587899fd8b42a4c318b4667/html5/thumbnails/17.jpg)
Инструментирование (5) • Директивы, ссылающиеся на исходный файл,
вставляются инструментатором в сгенерированный метод
• Это позволяет использовать пошаговую отладку
• Ограничение: нельзя с помощью Step Over перейти через точку разрыва
![Page 18: Zagursky](https://reader034.vdocuments.net/reader034/viewer/2022052412/5587899fd8b42a4c318b4667/html5/thumbnails/18.jpg)
Исключения • Рантайм ловит все исключения, вылетевшие из
Async-метода
• Исключение заворачивается в служебный объект
• При запросе результата вызывающим Async-методом исключение выбрасывается заново
• Если исключение вылетает за пределы файбера, то это диагностируется как ошибка
![Page 19: Zagursky](https://reader034.vdocuments.net/reader034/viewer/2022052412/5587899fd8b42a4c318b4667/html5/thumbnails/19.jpg)
Прерывание файбера • В каждой точке входа в Async-метод
проверяется, не был ли прерван текущий файбер
• Если файбер был прерван, то выбрасывается служебное исключение FiberInterruptedException
![Page 20: Zagursky](https://reader034.vdocuments.net/reader034/viewer/2022052412/5587899fd8b42a4c318b4667/html5/thumbnails/20.jpg)
Функции FiberManager • Планировщик
• Обрабатывает приостановку, возобновление и прерывание файберов
• У всех файберов одинаковый приоритет
![Page 21: Zagursky](https://reader034.vdocuments.net/reader034/viewer/2022052412/5587899fd8b42a4c318b4667/html5/thumbnails/21.jpg)
Гарантии FiberManager • Файберы должны исполняться в порядке
добавления и возобновления
• Приостановленные файберы не должны исполняться
![Page 22: Zagursky](https://reader034.vdocuments.net/reader034/viewer/2022052412/5587899fd8b42a4c318b4667/html5/thumbnails/22.jpg)
Thread safety • Методы scheduleFiber() и resumeFiber()
могут выполняться из любого потока
• Все остальные методы – только из потока, к которому привязан планировщик
• На каждый поток есть свой планировщик
![Page 23: Zagursky](https://reader034.vdocuments.net/reader034/viewer/2022052412/5587899fd8b42a4c318b4667/html5/thumbnails/23.jpg)
StackTrace (1) • Stack trace из new Throwable().getStackTrace() не
достаточен • Программист хочет видеть:
– стек Async-методов – стек в момент порождения файбера
• Файбер может быть создан внутри другого файбера • Stack trace должен разрешаться (resolve) только
тогда, когда он реально необходим
![Page 24: Zagursky](https://reader034.vdocuments.net/reader034/viewer/2022052412/5587899fd8b42a4c318b4667/html5/thumbnails/24.jpg)
StackTrace (2) • Рантайм получает уже готовое исключение
• К этому исключению нужно добавить
– стек файбера
– стек момента порождения файбера
• Используется addSuppressed()
![Page 25: Zagursky](https://reader034.vdocuments.net/reader034/viewer/2022052412/5587899fd8b42a4c318b4667/html5/thumbnails/25.jpg)
StackTrace (3) • Переопределяется метод fillInStackTrace(),
чтобы не собирать обычный stack trace
• Массив StackTraceElement[] формируется только по запросу getCause() и при сериализации
![Page 26: Zagursky](https://reader034.vdocuments.net/reader034/viewer/2022052412/5587899fd8b42a4c318b4667/html5/thumbnails/26.jpg)
java.lang.Throwable at asserts.Verify.fail(Verify.java:47) at gm.cc.c.t.CmdTeleportRandomByMapType.asyncRun$Async(CmdTeleportRandomByMapType.java:152) at gm.cc.c.t.CmdTeleportRandomByMapType$Context_asyncRun_LmsgSystem#locales#Abonent_.update(CmdTeleportRandomByMapType.java) at f.i.AsyncImpl.updateSafe(AsyncImpl.java:37) at f.i.FiberImpl.updateInternal(FiberImpl.java:154) at f.i.FiberImpl.update(FiberImpl.java:130) at f.i.FiberManagerAbstract.updateFiber(FiberManagerAbstract.java:297)
... at java.lang.Thread.run(Thread.java:722) Suppressed: f.i.FiberStackTraceHolderException: Fiber stack trace Caused by: f.i.FiberStackTraceHolderException$Helper at asserts.Verify.fail(Verify.java:47) at gm.cc.c.t.CmdTeleportRandomByMapType.asyncRun(CmdTeleportRandomByMapType.java:141) at ms.l.AsyncMsg.run(AsyncMsg.java:37) at ms.i.mp.ServerMsgPublisher.processMsg(ServerMsgPublisher.java:331) at ms.i.mp.ServerMsgPublisher.addMsgFast(ServerMsgPublisher.java:118) ... at java.lang.Thread.run(Thread.java:722)
![Page 27: Zagursky](https://reader034.vdocuments.net/reader034/viewer/2022052412/5587899fd8b42a4c318b4667/html5/thumbnails/27.jpg)
Узкие места (1) • Инструментатор меняет сигнатуру метода • Служебные методы call() и result() вырезаются,
чтобы байткод соответствовал новой сигнатуре • Об этом не догадывается IntelliJ Idea, которая
вставляет проверки на != null • Инструментатор вырезает такие проверки из
Async-методов
![Page 28: Zagursky](https://reader034.vdocuments.net/reader034/viewer/2022052412/5587899fd8b42a4c318b4667/html5/thumbnails/28.jpg)
Узкие места (2) • Если Async-метод декларирует throws
SomeUncheckedException – синтаксис java потребует его обработки
– catch-блок для этого исключения никогда не будет вызван
– исключение пролетит в рантайм, т. к. для него нет соответствующего catch
![Page 29: Zagursky](https://reader034.vdocuments.net/reader034/viewer/2022052412/5587899fd8b42a4c318b4667/html5/thumbnails/29.jpg)
Узкие места (3) • Синтаксис не запрещает вызов Async-
метода из обычного
• Вызываемый метод не исполнится
![Page 30: Zagursky](https://reader034.vdocuments.net/reader034/viewer/2022052412/5587899fd8b42a4c318b4667/html5/thumbnails/30.jpg)
Узкие места (4) • Точки разрыва не могут быть в блоке finally
• Причина: в этом случае исключение может быть проигнорировано
![Page 31: Zagursky](https://reader034.vdocuments.net/reader034/viewer/2022052412/5587899fd8b42a4c318b4667/html5/thumbnails/31.jpg)
Альтернативные решения • Apache Javaflow
• DaVinci VM
• Kilim
![Page 32: Zagursky](https://reader034.vdocuments.net/reader034/viewer/2022052412/5587899fd8b42a4c318b4667/html5/thumbnails/32.jpg)
Сергей Загурский
в е д у щ и й п р о г р а м м и с т, п р о е к т S k y f o r g e
s . z a g u r s k i y @ c o r p . m a i l . r u