OberonCore

Библиотека  Wiki  Форум  BlackBox  Компоненты  Проекты
Текущее время: Вторник, 22 Октябрь, 2019 02:25

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 33 ]  На страницу 1, 2  След.
Автор Сообщение
 Заголовок сообщения: Многопоточность и сборщик мусора
СообщениеДобавлено: Четверг, 31 Май, 2018 12:17 

Зарегистрирован: Пятница, 13 Март, 2009 16:36
Сообщения: 819
Откуда: Казань
Современные процессоры содержат все больше и больше ядер. И для того, чтобы эффективно использовать имеющиеся ресурсы, необходимо разрабатывать параллельные (многопоточные) программы, которые за счет использования нескольких ядер, будут выполняться быстрее. В принципе, как сделать параллельное выполнение более-менее понятно. Единственная сложность это использование сборщика мусора. Если при однопоточном режиме, во время работы сборщика мусора вся остальная программа не выполняется, то при многопоточном режиме этого нет.
Какие есть варианты:
1) Приостановить все потоки и собирать мусор. Но даже здесь, может возникнуть сложность. Так как, если при однопоточном режиме, сборщик мусора, обычно запускается при вызове функции NEW или же вызывается какая функция, когда система проставивает, то есть сборка мусора происходит в строго определенных местах программы. То при остановке потоков, они могут остановиться где попало и может так быть, что какие-то значения скопированы в регистры, например. И значения в регистрах тоже надо будет анализировать на предмет того, а не является ли он указателем. И, если при анализе стека, можно реализовать какие-то дескрипторы, которые будут говорить, где именно хранятся указатели, а где просто числовые переменные. И таким образом, можно реализовать, точный сборщик мусора, то с регистрами так не получится, и получится только реализовать консервативный сборщик мусора.
2) Или же надо реализовывать какой-то параллельный сборщик мусора, например, такой, который описан у Дейкстры. Но насколько я понимаю, он тоже приостанавливает все потоки, чтобы собрать только корневые указатели, а дальше уже потоки можно отпустить.
3) Может быть есть еще какие-то варианты.

По идее хотелось бы иметь очень простое, но надежное решение.
Кто-нибудь уже думал над проблемой сборки мусора для многопоточных приложений?


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 31 Май, 2018 13:41 

Зарегистрирован: Четверг, 08 Май, 2008 19:13
Сообщения: 909
Откуда: Киев
Надёжная многопоточность в императивных программах может быть только в виде изолированных друг от друга потоках, общающихся обменом сообщений. Разделять память в прямом виде они между собой не должны. Соответственно, сборка мусора должна быть отдельно в каждом потоке. В некоторых потоках сборка памяти даже не нужна - начали поток, что-то сделали, завершили с автоматическим освобождением всего клубка. Дело, кстати не только в многопоточности. Можно и в одном потоке запускать изолированную задачу, которая освобождает выделенную память по завершению. Также, это даёт возможность более безопасной обработки исключительных ситуаций, потому что из-за изолированности памяти у нас есть гарантия отсутствия в базовом процессе структуры с нарушенными инвариантами из-за прерванной обработки.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 31 Май, 2018 14:36 

Зарегистрирован: Пятница, 13 Март, 2009 16:36
Сообщения: 819
Откуда: Казань
Comdiv писал(а):
Надёжная многопоточность в императивных программах может быть только в виде изолированных друг от друга потоках, общающихся обменом сообщений.

С этим согласен.

Comdiv писал(а):
Разделять память в прямом виде они между собой не должны.

С этим не совсем согласен.
Если память не разделять, то необходимо копировать все передаваемые сообщения. Допустим, есть какая-то большая структура данных, которая занимает 500 Мб, чтобы параллельный компонент что-то мог бы с ним сделать, необходимо передать ему эту структуру, то есть произойдет копирование 500 Мб памяти, а затем в обратную сторону еще раз копирование 500 Мб. Если же разделять память, то достаточно просто передать один указатель и отметить у себя в потоке, что пока другой поток не перестанет с ним работать, то с этой структурой данных ничего делать нельзя. И в обратную сторону также будет передан только один указатель.

Есть еще аргументы в пользу разделения памяти. Допустим, в разные моменты времени у программы, может быть несколько потоков (Аналог параллельного запуска нескольких компонент через parbegin и завершения после parend). Допустим, при старте программы, запускается один поток, который что-то инициализирует, а затем запускает несколько потоков, которые параллельно работают. Если память не разделять, то для передачи данных от основной программы в потоки также будет необходимо копировать все данные. Затем, если потоки поработали и сформировали какой-то результат, то при завершении этих потоков и при возврате снова в однопоточный режим, опять нужно будет копировать данные.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 31 Май, 2018 14:50 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2604
Откуда: Россия, Ярославль
В golang в том году сделали параллельный сборщик без stop world, кажется.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 31 Май, 2018 15:05 

Зарегистрирован: Четверг, 08 Май, 2008 19:13
Сообщения: 909
Откуда: Киев
Rifat писал(а):
Если память не разделять, то необходимо копировать все передаваемые сообщения
Придётся проектировать программу так, что разделять не нужно было. Это надо просто принять, либо коренным образом переделывать язык, например, переходом в другую парадигму.

Если так уж получается, что разделять всё-таки нужно в рамках императивной логики, то нужно выделить третий поток, который будет владеть общими данными и обеспечивать работу с остальными клиентами. Как и проектирование модульной системы вместо сваливания всего в одну кучу, это может потребовать большИх усилий на проектирование, но, на мой взгляд, только так и нужно делать для создания не наколенных-скриптовых решений. Это, во многом, будет похоже на работу с базой данных, если, вообще, этот третий поток и не будет готовой СУБД.

С общими инициализированными данными тоже есть всякие ухищрения вроде копирования по записи.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 31 Май, 2018 15:15 

Зарегистрирован: Пятница, 13 Март, 2009 16:36
Сообщения: 819
Откуда: Казань
Comdiv писал(а):
Соответственно, сборка мусора должна быть отдельно в каждом потоке.

Я понял вашу идею.

А в плане перспективности что лучше: отдельный сборщик мусора в каждом потоке или подход из GoLang, когда есть общая память и параллельный сборщик мусора?


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 31 Май, 2018 16:46 

Зарегистрирован: Четверг, 08 Май, 2008 19:13
Сообщения: 909
Откуда: Киев
Я потому и завёл разговор об изолированных потоках, что считаю такой подход более переспективным.
В Go, насколько помню, остановки есть, но короткие, и, в целом, расход процессорного времени на сборку только увеличился, но стал размазанным во времени, что уменьшило его критичность.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 31 Май, 2018 16:57 

Зарегистрирован: Пятница, 13 Март, 2009 16:36
Сообщения: 819
Откуда: Казань
Если память у потоков должна быть раздельной, то тогда, наверно, надо придумать какой-нибудь механизм, чтобы нельзя было через сообщения между потоками передать указатель. А при обращении одного потока, к памяти другого потока, чтобы возникало сообщение об ошибке.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 31 Май, 2018 17:20 

Зарегистрирован: Четверг, 08 Май, 2008 19:13
Сообщения: 909
Откуда: Киев
По-моему, в языках с герметичными данными это обеспечивается по умолчанию, и ничего дополнительного придумывать не нужно. Нет?


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 31 Май, 2018 18:09 

Зарегистрирован: Пятница, 13 Март, 2009 16:36
Сообщения: 819
Откуда: Казань
Вроде нет. Взять, допустим, BlackBox или какой-нибудь из компиляторов Oberon-07 там можно реализовать параллельную работу, посредством создания потоков. Это можно сделать без изменения компилятора, достаточно написать определенную библиотеку. Но, то как компилятор обрабатывает вызов NEW и как сборщик мусора находит корневые указатели, это не поменяет. Если требуется, чтобы у каждого параллельного компонента был свой сборщик мусора, то нужно, чтобы при вызове NEW, во-первых, система определяла из какого компонента был вызов и там распределяла память. А, во-вторых, в текущих реализациях исключение возникнет, если попытаться разыменовать нулевой указатель, но пока нет проверок на то, что один компонент пытается обратиться по адресу памяти, который создан в другом компоненте.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 31 Май, 2018 18:33 

Зарегистрирован: Четверг, 08 Май, 2008 19:13
Сообщения: 909
Откуда: Киев
Rifat писал(а):
Это можно сделать без изменения компилятора, достаточно написать определенную библиотеку
Средствами самого языка без SYSTEM?


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 31 Май, 2018 21:26 
Аватара пользователя

Зарегистрирован: Суббота, 12 Июль, 2008 22:49
Сообщения: 573
Откуда: Россия, Санкт-Петербург
Для того чтобы можно было обсуждать сборку мусора в многопоточной среде в Обероне, нужно чтобы в Обероне была Модель Памяти. Но в Обероне нет Модели Памяти, соответственно обсуждать пока нечего. Например, Модель Памяти Go очень похожа на Модель Памяти Java для которой существует большое количество разнообразных сборщиков мусора. Современные сборщики мусора умеют почти обходиться без "остановки мира", собирая мусор в отдельном потоке.

Если язык допускает превращение произвольного адреса в ссылку, то сборщик мусора здесь не поможет.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 01 Июнь, 2018 09:45 

Зарегистрирован: Пятница, 13 Март, 2009 16:36
Сообщения: 819
Откуда: Казань
Comdiv писал(а):
Rifat писал(а):
Это можно сделать без изменения компилятора, достаточно написать определенную библиотеку
Средствами самого языка без SYSTEM?

В принципе да, можно обойтись практически без SYSTEM (SYSTEM может потребоваться только для вызова WinApi функций, например, CreateThread и.т.д., а, если работа с потоками уже реализована, то и SYSTEM использовать не придется). Тут, конечно, много оговорок, что сделать-то, это можно, но это потребует определенной дисциплины программирования.
Взять, например, семантику параллельного запуска программ, которые, если не ошибаюсь ввел Дейкстра:
Код:
parbegin
  proc1;
  proc2;
  proc3;
parend;

Конструкция parbegin параллельно запускает несколько процедур proc1, proc2, proc3.
Того же самого, можно добиться и без ввода новых конструкций в язык программирования, например, так:
Код:
library.Add(proc1);
library.Add(proc2);
library.Add(proc3);
library.ExecuteAll;

А уже внутри библиотеки будет определенный пул потоков, который будет использоваться для запуска каких-то задач. Также библиотека будет ответственна за передачу сообщений.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 01 Июнь, 2018 09:54 

Зарегистрирован: Пятница, 13 Март, 2009 16:36
Сообщения: 819
Откуда: Казань
Madzi писал(а):
Для того чтобы можно было обсуждать сборку мусора в многопоточной среде в Обероне, нужно чтобы в Обероне была Модель Памяти. Но в Обероне нет Модели Памяти, соответственно обсуждать пока нечего. Например, Модель Памяти Go очень похожа на Модель Памяти Java...

Просмотрел ссылки про "Модель Памяти". Как мне показалось, там больше не про память, а про модель параллельности: параллельность с общей памятью и про оптимизирующие компиляторы (или о ужас! процессоры!), которые могут переупорядочивать инструкции. А далее уже идут следствия, что если есть два потока, а инструкции внутри этих потоков упорядочены не так, как задумал программист, то "можно свободно ожидать чего угодно". А чтобы не было "чего угодно", то надо использовать синхронизирующие примитивы.

В этой же теме, чуть выше мы остановились на том, что распределенные или дистрибутивные программы без общей памяти, которые обмениваются сообщениями, позволяют создавать более надежный код. Как мне кажется, те проблемы, которые описаны в "Моделях Памяти" Go и Java, будут не актуальны в этом случае.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 01 Июнь, 2018 12:02 

Зарегистрирован: Четверг, 08 Май, 2008 19:13
Сообщения: 909
Откуда: Киев
Rifat писал(а):
В принципе да, можно обойтись практически без SYSTEM (SYSTEM может потребоваться только для вызова WinApi функций, например, CreateThread и.т.д., а, если работа с потоками уже реализована, то и SYSTEM использовать не придется).
Я это спрашивал к тому, что эти средства позволяют выйти за рамки основной модели языка(поломать). И то, что получится в итоге, уже не будет соостветствовать языку - это просто другой язык, хоть и похожий. Если в описания языка не сказано тем или иным орбазом, что память может меняться в промежутках между выполнением инструкций, меняющих указанные участки, то мы и не должны исходить из предположений, что это может происходить. Иначе можно предполагать всё что угодно, потому что каким бы подробным и точным описание не было, оно не может перечислить всё, что не должно происходить. Взаимодействие же в рамках изолированных потоков полностью вписывается в текущее описание.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 01 Июнь, 2018 12:04 
Аватара пользователя

Зарегистрирован: Суббота, 12 Июль, 2008 22:49
Сообщения: 573
Откуда: Россия, Санкт-Петербург
Общая память будет в любом случае (не по данным, а по коду), если потоки будут выполняться на одной машине, даже если потоки не будут иметь общих объектов.
Если же рассматривать совсем изолированные потоки, то чем это будет отличаться от двух ББ запущенных на разных машинах и обменивающихся данными через сеть ?
Для такого случая никакая многопоточность не нужна.

А модель памяти всегда отвечает на вопрос, "Что будет прочитано из конкретной переменной в конкретном потоке", чтобы можно было программу верифицировать. Естественно там будет много про синхронизацию. И да, даже если инструкции расположены в "правильном" порядке в машинном коде, то во время исполнения на уровне процессора они могут быть переупорядочены, если менеджер процессора посчитает, что выполнение "следующей" инструкции не зависит от "предыдущей"


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 01 Июнь, 2018 15:09 

Зарегистрирован: Четверг, 08 Май, 2008 19:13
Сообщения: 909
Откуда: Киев
Madzi писал(а):
Если же рассматривать совсем изолированные потоки, то чем это будет отличаться от двух ББ запущенных на разных машинах и обменивающихся данными через сеть ?
На базовом уровне - ничем, в деталях всё же будет. Отсутствие базовых отличий - это дополнительное преимущество.
Цитата:
Для такого случая никакая многопоточность не нужна.
Здаётся мне, Вы под многопоточностью понимаете какое-то более узкое понятие. Так-то это тоже многопоточность, которая нужна.
А так, главное, что хотелось донести - не стоит тратить силы на решение, которое на самом деле и не нужно.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Суббота, 02 Июнь, 2018 14:54 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9147
Откуда: Россия, Орёл
Кроме изолированных по памяти потоков (можно в общем адресном пространстве - например, несколько ББ в одном процессе, что позволяет никогда не пересечься по указателям, но иметь спокойно общие массивы чего-нибудь, например, для вычислительной обработки или быстрого обмена сообщениями), приемлемы ещё "зелёные потоки", например, для ББ - это подходы с сопрограммами, Дмитрия Дагаева и мой.

Если у вас поток выполнения не произвольный, а перемежённый ручными передачами управления диспетчеру, то не возникает проблемы "а в подоходящем ли месте заморозили поток для сборки мусора" (иначе, действительно, приходится дёргать туда-сюда поток, смотреть контекст и т.п. - так делалось в Active BlackBox).

Ну, это, естественно. не для случая жёсткого реального времени. Там выделение памяти и сборка мусора должны быть выключены после старта. И дальше - только фиксированное число объектов. Если для задачи они нужны в переменном по времени количестве - то они крутятся в пулах.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 04 Июнь, 2018 11:59 

Зарегистрирован: Четверг, 08 Май, 2008 19:13
Сообщения: 909
Откуда: Киев
Илья Ермаков писал(а):
Кроме изолированных по памяти потоков (можно в общем адресном пространстве - например, несколько ББ в одном процессе, что позволяет никогда не пересечься по указателям, но иметь спокойно общие массивы чего-нибудь, например, для вычислительной обработки или быстрого обмена сообщениями)
Это если рассматривать проблему с точки зрения сложности работы сборщика мусора. Если рассматривать с точки зрения надёжности, то общего адресного пространства, доступного для записи, не должно быть.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 07 Июнь, 2018 01:53 

Зарегистрирован: Четверг, 08 Май, 2008 19:13
Сообщения: 909
Откуда: Киев
Словно в подтверждение мне довелось столкнуться с блуждающей ошибкой, связанной с многопоточным доступом к разделяемой памяти, которая была в библиотеке построения графиков для Android. Ошибка существовала с 2010 года, и только сейчас она будет исправлена, если автор примет исправление https://github.com/ddanny/achartengine/pull/530

Ошибки с разделяемой памятью можно отнести к разновидности ошибок порчи памяти.


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 33 ]  На страницу 1, 2  След.

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Вся информация, размещаемая участниками на конференции (тексты сообщений, вложения и пр.) © 2005-2019, участники конференции «OberonCore», если специально не оговорено иное.
Администрация не несет ответственности за мнения, стиль и достоверность высказываний участников, равно как и за безопасность материалов, предоставляемых участниками во вложениях.
Без разрешения участников и ссылки на конференцию «OberonCore» любое воспроизведение и/или копирование высказываний полностью и/или по частям запрещено.
Powered by phpBB® Forum Software © phpBB Group
Русская поддержка phpBB