Concurrency и многопоточность
Я не очень разбираюсь в таких предметах, как Concurrency и многопоточность. Фактически, в большинстве моих карьерных карьеры в Интернете мне никогда не приходилось касаться этих предметов.
Я чувствую, что это важная концепция, особенно для настольных приложений и в основном любое другое приложение, которое не генерирует HTML:).
После чтения бит на concurrency он лучше поддерживается на таких языках, как Go (язык программирования google), и я не совсем понимаю, почему язык был бы лучше, чем другие, в концепции типа concurrency, так как это в основном о возможности процессов fork() и вычислить материал параллельно, не так ли? Разве это не так, как работает программирование?
Многопоточность, по-видимому, является ветвью Concurrency, поскольку она позволяет вам запускать операции параллельно под одним и тем же процессом, хотя, по-видимому, это зависит от платформы, как она реализована.
Я думаю, что мой вопрос: , почему конкретные языки будут лучше на Concurrency, чем другие, и почему бы процессы fork() были лучшим решением, а не просто использованием потоков?
Ответы
Ответ 1
Ну, во-первых, несколько потоков - это не то же самое, что несколько процессов, поэтому fork() действительно здесь не применяется.
Многопоточная/параллельная обработка сложна. Сначала вам нужно выяснить, как на самом деле разделить задачу, которую нужно выполнить. Затем вам необходимо координировать все параллельные биты, которые могут потребоваться для общения друг с другом или совместного использования ресурсов. Затем вам нужно консолидировать результаты, которые в некоторых случаях могут быть настолько сложными, как предыдущие два шага. Я упрощаю здесь, но, надеюсь, вы поняли эту идею.
Итак, ваш вопрос: почему некоторые языки будут лучше в этом? Ну, несколько вещей могут сделать это проще:
-
Оптимизированные неизменные структуры данных. Вы хотите придерживаться неизменных структур, когда это возможно, в параллельной обработке, потому что их гораздо легче рассуждать. Некоторые языки имеют лучшую поддержку для них, а некоторые из них имеют различные оптимизации, то есть возможность объединения коллекций вместе без какого-либо фактического копирования при сохранении неизменности. Вы всегда можете создавать свои собственные структуры, подобные этим, но это проще, если язык или структура делает это для вас.
-
Примитивы синхронизации и простота их использования. Когда разные потоки делят состояние, они должны быть синхронизированы, и есть много разных способов сделать это. Чем шире массив примитивов синхронизации, тем проще будет ваша задача. Производительность будет иметь успех, если вам нужно синхронизировать с критическим сектором вместо блокировки чтения-записи.
-
Атомные транзакции. Даже лучше, чем широкий набор примитивов синхронизации, не нужно использовать их вообще. Двигатели баз данных очень хороши в этом; а не вам, программисту, нужно точно определить, какие ресурсы вам нужно блокировать, а когда и как, вы просто говорите компилятору или интерпретатору, "все вещи ниже этой строки должны происходить вместе, поэтому убедитесь, что никто другой беспорядок с ним, пока я использую его". И двигатель будет определять блокировку для вас. Вы почти никогда не получаете такую простоту в абстрактном языке программирования, но чем ближе вы можете прийти, тем лучше. Объекты, защищенные потоками, которые объединяют несколько общих операций в один, являются началом.
-
Автоматический parallelism. Скажем, вам придется перебирать длинный список предметов и каким-то образом преобразовывать их, например умножать 50 000 матриц 10x10. Было бы неплохо, если бы вы могли просто сказать компилятору: Эй, каждая операция может быть выполнена независимо, поэтому используйте отдельное ядро процессора для каждого из них? Не нужно ли фактически выполнять потоки самостоятельно? Некоторые языки поддерживают такие вещи; например, команда .NET работает над PLINQ.
Это всего лишь несколько примеров того, что может сделать вашу жизнь проще в параллельных/многопоточных приложениях. Я уверен, что есть еще много.
Ответ 2
В языках, которые не предназначены для concurrency, вы должны полагаться на низкоуровневые системные вызовы и самостоятельно управлять многими вещами. Напротив, язык программирования, разработанный для concurrency, например, Erlang, предоставит высокоуровневые конструкции, которые скрывают детали низкого уровня. Это упрощает рассуждение о правильности кода, а также приводит к более переносимому коду.
Кроме того, на языке программирования, разработанном для concurrency, обычно существует только несколько способов сделать параллельные вещи, что приводит к последовательности. Напротив, если язык программирования не был разработан для concurrency, тогда разные библиотеки и разные программисты будут делать что-то по-другому, затрудняя выбор способов их выполнения.
Это немного похоже на разницу между языком программирования с автоматизированной сборкой мусора и без него. Без автоматизации программист должен много думать о деталях реализации.
Разница между многопотоковым программированием и многопроцессорным программированием (то есть fork()) заключается в том, что многопоточная программа может быть более эффективной, поскольку данные не должны передаваться через границы процесса, но многопроцессорный подход может быть более надежным.
Ответ 3
Что касается вашего вопроса о том, почему fork()
вместо потоковой передачи: при использовании отдельных процессов вы получаете автоматическое разделение адресных пространств. В многопоточных программах очень часто для потоков сообщается использование их (естественно) разделяемой памяти. Это очень эффективно, но также трудно получить правильную синхронизацию между потоками, и поэтому некоторые языки лучше подходят для многопоточности, чем другие: они обеспечивают лучшие абстракции для обработки распространенных случаев связи между потоками.
С отдельными процессами у вас нет таких проблем в той же степени. Как правило, вы устанавливаете связь между процессами, чтобы следовать какой-то форме шаблона передачи сообщений, что становится проще. (Ну, вы также можете использовать разделяемую память между процессами, но это не так часто, как передача сообщений.) В системах Unix fork()
обычно было очень дешево, поэтому традиционный дизайн параллельных программ в Unix использует процессы и каналы для связи между но в системах, где создание процесса является дорогостоящей операцией, потоки часто рассматриваются как лучший подход.
Ответ 4
Я изучаю предмет (прямо сейчас: D), и одна из вещей, которая кажется очень важным отличием между concurrency между языками, - это выразительная сила языка на concurrency.
Например, С++ не имеет встроенной поддержки concurrency и полагается на функции, предоставляемые ОС.
Java - это шаг выше, потому что есть некоторые встроенные методы, в то время как другие остаются в ОС (например, планирование потоков или приоритет).
Вместо одним из лучших языков программирования, поддерживающим concurrency, является Ada, который на самом деле является целым concurrency -моделем, встроенным в ( планирование и приоритет).
Почему это важно? Из-за переносимости!
Использование языка с хорошей выразительной мощностью concurrency позволяет вам принести вашу параллельную программу в Windows, Linux или Mac с большими опасениями о том, как она будет работать.
Например: приоритет потока будет применяться в одинаковом в вашей программе Ada, работающей в Windows, Linux или Mac, в то время как он может быть действительно другим (игнорируется в некоторых ОС и применяется в других) с Java или С++.
Это то, что мне кажется по курсу, который я сейчас беру в университете:)
Ответ 5
Re: почему некоторые языки лучше для concurrency, чем другие: все зависит от инструментов, которые язык предлагает программисту. Некоторые языки, такие как С++, предоставляют вам низкоуровневый доступ к системным потокам. Java имеет все виды библиотек, которые предлагают конструкции для параллельного программирования, вроде шаблонов проектирования (см. "Защелка", "Барьер" и др.). Некоторые языки облегчают работу с потоками. Некоторые языки не позволяют вам разделять состояния между потоками, что является основным источником ошибок.
И тогда некоторые языки имеют разные основные модели потоков, чем другие. Модель потока Python, как я понимаю, использует один системный поток и обрабатывает все самопересечение контекста, которое не так чисто, как только оно является таким же гранулярным, как и одна инструкция Python.
Как аналог, он спрашивает, почему некоторые языки лучше справляются с регулярными выражениями, или ищут, либо выполняют сложную математику, когда в конце ее все только движущиеся биты вокруг.
Изменить: frunsi правильно, потоки Python - системные потоки (видимо, это распространенное заблуждение). Проблема, о которой я говорил, была связана с блокировкой GIL или глобальным интерпретатором, которая контролирует выполнение потоков. Только один поток может запускаться в интерпретаторе Python одновременно, и контекст переключается только между инструкциями. Мои знания о многопоточности Python в основном проистекают из этой статьи: www.dabeaz.com/python/GIL.pdf. Может быть, немного не по теме, но хорошая рекомендация тем не менее.
Ответ 6
В fork человеческий поток является божественным: D
Викинг включает ядро и создает отдельное пространство адресов - значит, что X и Y не могут легко делиться и использовать примитивы IPC, а создание потока позволяет в синхронизации процессов, которая быстрее FAR, чем IPC, которая включает в себя контекст ядра переключатели обоими процессами и ненужный выход потока (которые включают ядро, чтобы разбудить упомянутую нить вверх).
Однако существует множество причин, по которым разные модели concurrency лучше других. Я просто даю вам общее правило для общего программирования. Например, не форсинг может поставить под угрозу логику, которая может быть отделена путем форкирования (я люблю это слово) - под угрозой, потому что, если другая логика процесса выйдет из строя, хорошо сказанная логика идет вниз с процессом.
Ответ 7
ни один язык не лучше другого, все о понятиях. Выполнение вещей одновременно процессами потребляет обычно больше ресурсов, чем потоки (которые можно рассматривать как легкие процессы), на некоторых языках легко использовать библиотеки libs.
Java-потоки слишком просто используются, потоки Posix (C on unix) немного сложнее.
Ответ 8
Concurrency в основном может обрабатывать процессы fork() и вычислять материал параллельно, так как управление памятью в основном может вызвать malloc. Это часть истории, но не все. Возможность упростить проблемы, связанные с concurrency, заключается в различии между языками, которые хороши в concurrency, и теми, которые могут быть одновременно.
Ответ 9
Выбор языка зависит от приложения, которое вы хотите сделать.
Вы хотите создать масштабируемую систему с множеством входящих "запросов"? Тогда Эрланг может быть хорошим выбором. Известно, что он хорошо подходит для сценариев приложений с высокой степенью параллелизма.
Если вы хотите написать типичную игру и хотите, чтобы она использовала теперь типично доступные двухъядерные или четырехъядерные процессоры вашей аудитории, тогда вы связаны с различными решениями (фреймворками, движками, библиотеками, доступными аппаратными интерфейсами). В этом случае вы будете использовать потоки, а пулы потоков - для разгрузки обработки. Скорее всего, вы будете использовать своего рода очередь сообщений для связи между потоками.
В (серверной) веб-разработке вы, скорее всего, уже получили некоторый опыт параллельного программирования! Возможно, вы не знали об этом, потому что язык и данные рамки (возможно, Apache и PHP) предоставили вам среду, которая сняла с вас бремя.