Помимо пунктов, упомянутых в других ответах (трудно доказать, что операции независимы, а программисты думают последовательно), существует еще один фактор, который необходимо учитывать: стоимость распараллеливания.
Правда в том, что параллелизм потоков имеет очень значительные затраты, связанные с ним:
Создание потока очень дорого: для ядра запуск потока примерно такой же, как запуск процесса. Я не уверен насчет точных затрат, но я верю, что это порядка десяти микросекунд.
Связь между потоками через мьютексы обходится дорого: обычно для этого требуется системный вызов с каждой стороны, возможно, перевести поток в спящий режим и снова разбудить его, что приводит к задержке, а также кешу и холодным TLB. В среднем, взятие и освобождение мьютекса стоит около одной микросекунды.
Все идет нормально. Почему это проблема для неявного параллелизма? Потому что неявный параллелизм легче всего доказать в небольших масштабах. Одно дело доказать, что две итерации простого цикла независимы друг от друга, совсем другое дело доказать, что печать чего-либо stdout
и отправка запроса в базу данных независимы друг от друга и могут выполняться параллельно ( процесс базы данных может быть на другой стороне трубы!).
Таким образом, неявный параллелизм, который может доказать компьютерная программа, вероятно, нецелесообразен, поскольку затраты на распараллеливание больше, чем преимущество параллельной обработки. С другой стороны, крупномасштабный параллелизм, который действительно может ускорить приложение, не доказуем для компилятора. Подумайте, сколько работы процессор может выполнить за микросекунду. Теперь, если предполагается, что распараллеливание будет быстрее, чем последовательная программа, параллельная программа должна быть в состоянии поддерживать все процессоры занятыми в течение нескольких микросекунд между двумя вызовами мьютекса. Это требует очень грубого параллелизма, который почти невозможно доказать автоматически.
Наконец, нет правила без исключения: использование неявного параллелизма работает там, где не задействованы потоки, как в случае с векторизацией кода (с использованием наборов команд SIMD, таких как AVX, Altivec и т. Д.). Это действительно работает лучше всего для небольшого параллелизма, который относительно легко доказать.