Обмен сообщений вместо разделяемой памяти
(В оригинале - Message Passing Leads to Better Scalability in Parallel Systems)
Программистам говорят с самого начала их обучения, что параллельные вычисления – это сложно, что только лучшие могут с этим совладать, и даже они все равно будут делать ошибки. При этом особое внимание уделяется потокам, семафорам, мониторингу и сложности обеспечения безопасного параллельного доступа к переменным.
Да, действительно, в этом много проблем и эти проблемы сложно решаются. Но что является источником всех проблем? Общая память. Практически все проблемы параллельного программирования вырастают из общей изменяемой памяти: гонки (race condition), блокирования (deadlocks) и прочее. Решение же очень простое: выбирайте что-то одно. Или параллелизм, или общую память.
Как вы понимаете, отказ от параллельного программирования – не вариант. Компьютеры обзаводятся все большим и большим количеством ядер, поэтому параллельное программирование становится все более важным. Мы не можем продолжать надеяться на повышение частот процессоров для повышения производительности. И только параллельные вычисления позволяют повышать производительность и далее. Конечно, можно отказаться от повышения производительности, но вряд ли это понравится пользователям.
Получается, что нам нужно отказаться от общей памяти.
Вместо использования потоков и общей памяти нам нужно перейти к модели процессов и передачи сообщений. Под процессом тут подразумевается защищенный независимый код, а не процесс операционной системы. Языки вроде Erlang показали, что процессы – очень удачный механизм для программирования многозадачных систем. У таких систем отсутствуют проблемы синхронизации, обычные для систем с потоками и разделяемой памятью. Более того, существует формальная модель коммуникации последовательных процессов (Communication Sequential Processes), использующаяся при разработке подобных многозадачных систем.
Мы можем пойти дальше и представить системы с потоками данных как способ вычислений. В системах с потоками данных не существует заданного потока вычислений. Вместо этого задается граф операторов, соединенных путями данных, после чего данные поступают в систему. Процесс контролируется готовностью данных. И никаких проблем синхронизации.
Однако системные языки вроде C, C++, Java, Python представляются программистам как языки для разработки многопоточных приложений с распределенной памятью. Что же с этим делать? Ответ – использовать (а если таковых не будет – то создавать) библиотеки и фреймворки, предоставляющие модель процессов и передачи сообщений и избегающие использования общей изменяемой памяти.
Программирование с использованием сообщений вместо разделяемой памяти – наиболее успешный способ разработки параллельных систем, преобладающих сейчас компьютерной индустрии. Возможно, что в будущем потоки будут использовать для реализации процессов, как бы странно это сейчас не звучало.
Автор оригинала - Russel Winder