Виждат ли се всички странични ефекти от задачите на изпълнителя след invokeAll?

Ако изпратя някои задачи на Executor с помощта на invokeAll, гарантирам ли ми, че изпратената нишка вижда всички странични ефекти от изпълнението на задачата, дори ако не извикам get() на всяко от върнатите Futures?

От практическа гледна точка изглежда, че това би било полезна гаранция, но не виждам нищо в javadoc.

По-точно, всички действия в тялото на Callable, изпратено до изпълнител, се случват-преди връщането от invokeAll() извикването?

Досадно е да се извиква безполезно get() за всеки фючърс, когато всъщност типът връщане е Void и не се хвърлят изключения - цялата работа в се случва като странични ефекти.


person BeeOnRope    schedule 14.09.2011    source източник
comment
За бъдещи скитащи читатели просто исках да добавя нещо, което ми помогна да разбера това малко по-добре. Официалните документи на Oracle относно връзките случва-преди в JVM са тук под „Свойства за съгласуваност на паметта“: docs.oracle.com/en/java/javase/16/docs/api/java.base/java/util/ в раздела, озаглавен „Свойства на последователност на паметта“. Това също прави препратка към ExecutorService, Callable и Future и техните връзки преди случване. Благодаря, че зададохте този въпрос. Помогна ми да отговоря и на моя.   -  person junkie    schedule 14.07.2021


Отговори (2)


Ако invokeAny() обещае, че няма задачи, които все още се изпълняват, когато invokeAny() се върне, това ще бъде така: всички странични ефекти са видими.

За да може invokeAny() да знае, че всички задачи са изпълнени, той трябва да се е синхронизирал с тези нишки, което означава, че връщането на функциите става след завършване на задачите (и всичко, което се случва в задачата). Въпреки това API на „ExecutorSerive“ и „Future.cancel()“ не казва изрично какво се случва, когато отмените изпълнявана задача (по-специално: ще cancel() ще изчака ли с връщането, докато задачите спрат да се изпълняват. Фактът, че след извикване на cancel(), isDone() трябва да върне истина, означава, че cancel() няма да се върне, докато задачата действително не приключи изпълнението.

Още едно нещо, за което трябва да внимавате, е, че няма да знаете дали дадена задача някога е започнала изпълнение, когато използвате invokeAny() без да инспектирате Future обектите.

person Thirler    schedule 14.09.2011
comment
ОП попита за invokeAll(), а не за invokeAny() - person parsifal; 14.09.2011
comment
Да, съжалявам - използвах непоследователно и invokeAny(), и invokeAll() в първоначалния си въпрос и поправих това по-късно. Във всеки случай съм склонен да се съглася, че за да знае invokeAll(), че всички задачи са изпълнени, той трябва да се синхронизира с всяка нишка и това вероятно ще настрои случва-преди с всички по-ранни действия на нишката. Все още можете да си представите един вид „мързелива“ реализация, която отлага известно синхронизиране на повикването Future.get(), но формулировката, връщаща списък с фючърси, държащи техния статус и резултати, когато всички са завършени, изглежда изключва това. Прието! - person BeeOnRope; 28.09.2011

От документацията на ExecutorService:

Действия в нишка преди подаване на Runnable или Callable задача към ExecutorService се случват - преди каквито и да било действия, предприети от тази задача, които на свой ред се случват - преди резултатът да бъде извлечен чрез Future.get().

Докато чета това, има бариера в паметта при изпращане на задача, така че евентуално ще трябва да извикате get() на последната задача в списъка си, но не и на другите.

Въпреки това, тъй като извикването на get() е единственият начин да се определи дали задачата е завършена или хвърлена, аз пак бих го извикал на всеки Future, независимо от гаранциите за памет.

person parsifal    schedule 14.09.2011
comment
Е, в този случай можете да приемете, че моят Callable не може да хвърля. Не мисля, че има валидна концепция за последната задача, тъй като въпреки че изпращате задачите в някакъв ред и получавате Futures обратно в същия ред, техният завършващ ред не е дефиниран, тъй като някои задачите, разбира се, могат да работят по-дълго от други. - person BeeOnRope; 28.09.2011