- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
for (int i = 0; i < 15; i++) {
// Прикольное место, надо прокомментировать
// Если наша функция Fork() вернула true, то мы
// в дочернем процессе и форкаться больше не надо
// Форканье - это задача родителя
// Дети этим заниматься не должны
if (Fork()) break;
}
Чем бы дитя не тешилось, лишь бы не форкалось.
> Есть идеи, как улучшить?
Ну я в свое время, когда форкал процессы, вообще не возвращал управления из функции, подобной вашей Fork, в дочернем процессе:
должен получать указатель еще указатель на пул и ставить в очередь этого пула
{@see ExecutorService}
Ну по условиям моей задачи пул не требовался, а каждый раз нужен был новый процесс. Поэтому было реализовано именно так, а не иначе.
> должен получать указатель еще указатель на пул и ставить в очередь этого пула
Ну да, логично. Еще до кучи можно передать колбек, который вызовет пул, когда задача будет выполнена.
ПС надо бы сделать rebase для коментов )
Да, только тут процессы, а не потоки. В жабе такого из коробки нет. Вот за что люблю python - в нём есть решения практически на все случаи жизни:
Тем более ExecutorService - интерфейс
С этим будут основные проблемы.
>раздающий Future по Callable, используя пулл процессов.
Но действительно - зачем? Или я чего-то не пойму.
Потоки они ведь легковесные и проблем с ними меньше.
Ну в винде да, разница на порядки. А вот в линухе емнип форк медленнее птред_крейта всего раза в 2.
А вообще - если хочется хорошей изоляции, надежности, и возможности запустить каждую задачу под соотв. юзером ограничив ей видимость своей папкой (аля андроид), а еще надо запускать недоверенный код (аля ideone)... то потоки вообще не вариант.
P.S. А с future на процессах я так понимаю основная проблема будет в маршаллинге. Все что не Serializable, и не сможет прокачаться через пайп, в такую фьючу не пропихнешь, и результатом не вытащишь.
P.P.S. Шаренная память в этом случае не особо вариант, т.к. если обмен идет через маленькое окно - те же самые траблы что у пайпа, только код сложнее. А если всю расшарить - ну тогда проще и юзать потоки.
Именно. Необходимость сериализации данных между жабо-машинами ломает семантику ExecutorService, делая его реализацию на процессах просто невозможной. Ну и кросс-платформенное решение возможно, скорее всего, только при допиливании jre.
SecurityManager
> и возможности запустить каждую задачу
> ограничив ей видимость
Для ряда задач можно использовать ClassLoaderы. Правда там свои подводные камни.
Не жабой единой... все-таки тема этого раздела С++.
P.S. А SecurityManager спасёт от OutOfMemoryError?
P.P.S. В ведре есть нативные приложения и JNI, поэтому, видимо, они и не стали заморачиваться с менеджером безопасности, и сделали по юзеру на каждое приложение.
По меркам этого сайта мы не сильно ушли от темы :)
Хороший вопрос. Мне на ум приходят только разные извраты. Не буду озвучивать.
Очень хороший. Много думал. Наверное никак. Жаба сама по себе песочница, и они считают что риска для остальной системы нет.
>нативные приложения и JNI
Ну вот как раз для них оно и придумано. Все внешние обращения (в т.ч. LoadLibrary) там мониторятся.
А вот память кагбе внутренний ресурс JVM, который ограничен при запуске.
Ну вот поэтому для недоверенного кода и нужны процессы ;(
Иначе из-за одного неудачного треда, который (возможно непреднамеренно, из-за бага) выжрет всю память, просто распидорасит всю JVM вместе с невиновными тредами, которые тихо и мирно выполняли свою работу. Куча то у них общая.
> Все внешние обращения (в т.ч. LoadLibrary) там мониторятся.
И приходится либо убирать возможность запуска нативных программ и либ (т.к. с ними уже никакой секурити манагер не справится), как поступили в браузерах, или забить на менеджера безопасности, сделать по юзеру на прогу и запретить им лазить друг к другу, как поступили на ведре.
Хорошо, а как в других языках (тот же питон с пулом и мультипроцессами) решить такую задачу - поставить квоту на цп, память процесса?
в винде есть Job Objects
Ну его можно сделать при желании.
> в винде есть Job Objects
А в линухе есть setrlimit.
Так что хоть и os specific, но, по идее, можно на всех приличных осях...
P.S. Если же запускать жабомашины - то можно в параметрах и указать лимит памяти, получится более-менее кроссплатформенное решение. С CPU - хз.
> В жабе такого из коробки нет.
> осилит реализовать жабий ExecutorService, кроссплатформенно используя пулл процессов.
А в питоне есть такое кроссплатформенное решение "из коробки", которым можно ставить квоты по памяти на запускаемые процессы?
Других разумных применений такому расточительству как пул потоков я пока не вижу.
ну этот виндовый Job Objects умеет в ограничение CPU только чуть ли не с Шиндошс-8 только (http://bit.ly/VOXWJJ), а в XP - только ограничить user-time + sheduling class
собсно, setrlimit, судя по ману недалеко ушел от XP (RLIMIT_CPU + RLIMIT_NICE)
А так ли нужно это ограничение? Имхо достаточно искусственная вещь. При правильно розданных scheduling class'ах и так все будет нормально делиться, к тому же проц не будет зазря простаивать, если нет более приоритетной работы. Х.з. конечно, может быть я и ошибаюсь.
А так нормальное решение, почему бы нет?
Главное не забывать задокументировать где она стоит, что делает, и, по возможности, как. А то потом случаются не очень приятные истории, когда весь отдел сидит и пытается понять, нужен ли кому-то демон, конфиги и исходники которого последний раз правились лет 7-8 назад...
для *нихов это не костыль, это нормально. у меня где-то валяются сырцы сервера с пре-форком - там форк в самом условии while() вызывается. выглядит феерично, но суть та же: надо просто процессов дочерних процессов нафоркать, которые тупо в accept()е ждут запросов от клиентов.
> Лучше пулы юзать.
зависит от задачи. для многих простых вещей пул только усложнит программу. относительно плохая(*) производительность форка становится критичной только если делаешь что-то большое.
(*) относительно потоков.
Да и вообще мне не особо понятно зачем плодить процессы, если есть специально придуманные потоки? Единственный юзкейс, который я знаю - создание полной независимости частей приложения, табы в хроме, например.
фишка fork() как раз в том что его можно сделать легковесным. что почти все *нихи и делают. copy-on-write уж как лет десять везде реализован.
vfork() - я как бы и не уверен что он еще жив. сама идея vfork() была убогой. на паре *нихов и линухе это просто алиас для fork() потому что создание копии vma уже в самом fork() сделано ленивым.
ЗЫ vfork() в POSIX.6 - deprecated, POSIX.7 - non-existent.
ЗЗЫ линух реализовал vfork()! правда то как он работает это совсем не BSD vfork() - http://www.kernel.org/doc/man-pages/online/pages/man2/vfork.2.html
А вообще я в качестве лабы по ОС писал простенький веб-сервер, так вот, смена fork на vfork дала прирост производительности... О подробностях ничего не знал.
только что еще раз проверил. AIX и Линух - нету vfrok. (непортабельный линуховый vfork() не в счет.)
HP-UX & Solaris - есть, но (по традиции) зарезервирован только для последующего вызова exec() (но для HP-UX я точно видел официальное указание что разницы с fork()ом нету). та же песня в FreeBSD, но с нытьем в манпэйдже которое намекает что гондурасы все еще lazy vma copy не сделали: "The vfork() system call can be used to create new processes without fully copying the address space of the old process, which is horrendously inefficient in a paged environment."
ты по меркам этого треда кинул ссылку на далёкое светлое будущее
Изоляция. Можно запустить часть детей под нужным юзером, родитель не крашится при поломке одного ребенка и т.п. Часто ради этого приходится жертвовать производительностью. Хотя в линуксе время форка и время создания потока не сильно отличаются, в отличие от винды, где разница на порядки.
> Лучше уже vfork тогда
vfork, если мне не изменяет память, можно юзать только в сочетании с exec, по отдельности он бесполезен:
vfork() differs from fork(2) in that the parent is suspended until the child terminates (either normally, by calling _exit(2), or abnormally, after delivery of a fatal signal), or it makes a call to execve(2). Until that point, the child shares all memory with its parent, including the stack.
vfork уже выше обсудили, так что Вы опоздали )
Мда. И правда не блочит. Не зря там ниже написано: In particular, the programmer cannot rely on the parent remaining blocked until the child either terminates or calls execve(2), and cannot rely on any specific behavior with respect to shared memory..
Т.е. походу vfork можно юзать перед exec, чтобы получить небольшое ускорение на старых системах. А на новых он тупо ничем не отличается от fork.
UPD: сейчас переделаю тест, clock же измеряет не реальное время, а процессорное.
На моей машине выдает вот такое: Т.е. в vfork блокировка есть, в fork ее нет.
Ваш ход.
Хорошо, что не свои глаза.
p.s. интересно, страйко постарался или оно само восстанавливается?