Информация об изменениях

Сообщение Re[7]: Киллер фича JDK 21 - virtual threads от 10.05.2023 14:58

Изменено 10.05.2023 15:02 ·

Re[7]: Киллер фича JDK 21 - virtual threads
Здравствуйте, m2user, Вы писали:

M>Если же речь о коде, где нужно распараллелить операции, которые до этого выполнялись последовательно, то такой код понадобится раздробить на Runnable/Callable составляющие (функции или лямбды), попутно переписывая работу с переменными на стеке, возвратом результата, обработкой исключений.


M>Я утверждаю, что для такого кода:

M>1) по объему работы это не проще перевода на await/async
На порядок проще.
Вот у тебя код:
var details1 = someBigDao.complexBusinessLogicWhichDoesALotOfSQLQueriesSynchronously();
var details2 = someService.itGoesToNetworkAndDownloadsDataUsingSomeCrazySoapFramework();
return compbine(details1, details2);

В шарпе если ты такой код завернёшь в async, то толку никакого, т.к. первый же sql.execute() полезет синхронно в сокет и заблокирует твой async пока тот ждёт ответа от sql-сервера. Чтобы эти два метода запустить и чтобы они работали одновременно — тебе нужно запустить два честных треда.
Либо переписать всё на async-методы, чтобы они протаскивали Task по всему коду:
Т.е. если где-то внутре есть код типа
Result complexBusinessLogicWhichDoesALotOfSQLQueriesSynchronously()
{
  var r1 = sql.query(aaa);
  var r2 = sql.query(bbb);
  var r3 = sql.query(ccc);
  var r4 = anotherStuffWhichDoesSql(r2);
  return new Result(....);
}

то каждый sql.query тебе нужно придётся оборачивать в async и так по всей глубине стека.

С виртуальными тредами — ты просто пускаешь эти два метода и они работают параллельно:

var details1 = executor.submit(() -> someDao.complexBusinessLogicWhichDoesALotOfSQLQueriesSynchronously());
var details2 = executor.submit(() -> someService.downloadDataUsingSomeCrazySoapFramework()));
return combine(details1.join(), details2.join());

Всё. Ничего внутри someDao или someService менять не нужно.

M>2) await/async позволил бы писать более "плоский" код (меньше вложенных блоков кода)

M>Executors.newVirtualThreadPerTaskExecutor, которыей я упомянул в соседнем сообщении, частично облегчает ситуацию — с возвратом результата Callable и пробросом исключения (в виде ExecutionException)
Проброс исключений, callable и прочее не имеет никакого отношения к сабжу.
Re[7]: Киллер фича JDK 21 - virtual threads
Здравствуйте, m2user, Вы писали:

M>Если же речь о коде, где нужно распараллелить операции, которые до этого выполнялись последовательно, то такой код понадобится раздробить на Runnable/Callable составляющие (функции или лямбды), попутно переписывая работу с переменными на стеке, возвратом результата, обработкой исключений.


M>Я утверждаю, что для такого кода:

M>1) по объему работы это не проще перевода на await/async
На порядок проще.
Вот у тебя код:
var details1 = someBigDao.complexBusinessLogicWhichDoesALotOfSQLQueriesSynchronously();//работает 20 секунд
var details2 = someService.itGoesToNetworkAndDownloadsDataUsingSomeCrazySoapFramework();//работает 30 секунд
return compbine(details1, details2);//общее время 50 секунд

В шарпе если ты такой код завернёшь в async, то толку никакого, т.к. первый же sql.execute() полезет синхронно в сокет и заблокирует твой async пока тот ждёт ответа от sql-сервера. Чтобы эти два метода запустить и чтобы они работали одновременно — тебе нужно запустить два честных треда.
Либо переписать всё на async-методы, чтобы они протаскивали Task по всему коду:
Т.е. если где-то внутре есть код типа
Result complexBusinessLogicWhichDoesALotOfSQLQueriesSynchronously()
{
  var r1 = sql.query(aaa);
  var r2 = sql.query(bbb);
  var r3 = sql.query(ccc);
  var r4 = anotherStuffWhichDoesSql(r2);
  return new Result(....);
}

то каждый sql.query тебе нужно придётся оборачивать в async и так по всей глубине стека.

С виртуальными тредами — ты просто пускаешь эти два метода и они работают параллельно:

var details1 = executor.submit(() -> someDao.complexBusinessLogicWhichDoesALotOfSQLQueriesSynchronously());
var details2 = executor.submit(() -> someService.downloadDataUsingSomeCrazySoapFramework()));
return combine(details1.join(), details2.join());//общее время 30 секунд

Всё. Ничего внутри someDao или someService менять не нужно.

M>2) await/async позволил бы писать более "плоский" код (меньше вложенных блоков кода)

M>Executors.newVirtualThreadPerTaskExecutor, которыей я упомянул в соседнем сообщении, частично облегчает ситуацию — с возвратом результата Callable и пробросом исключения (в виде ExecutionException)
Проброс исключений, callable и прочее не имеет никакого отношения к сабжу.