В чем смысл запускать на Х-ядерном процессоре более Х потоков?
Т.к. одно ядро в 1 момент времени может обрабатывать только 1 операцию, то хоть разбивай программу на потоки, хоть не разбивай - это значит, что программа все-равно быстрее не выполнится, так? Допустим, мне нужно написать прогу для расчета 2х тяжелых операций, вычисление каждой занимает 10 сек. Если я запускаю вычисление обоих операций последовательно в одном потоке, то первая операция рассчитается и ее результат выведется через 10 сек, а результат второй выведется еще через 10 сек (оба результата в сумме будут готовы через 20 сек). Если я создам второй поток для расчета в нем второй операции, то ОС будет постоянно переключаться между двумя этими потоками, второй поток будет постоянно прерывать первый, а первый - второй, в итоге и первый, и второй результаты рассчитаются и выведутся только через 20 секунд оба (т.е получается, что создание второго потока только замедлит общую ситуацию?)
Понятие потоков же не недавно появилось, а очень давно, я думаю, что еще в 20 веке, но в середине 2000-х еще продавались компы с одноядерными процами. И я думаю, что уже в середине 2000-х было написано много программ, которые запускали кучу потоков, а выполняли эти проги на одноядерных процах. Вопрос - в чем в этом смысл??
Даже сейчас я, как прогер, вижу в исходниках, да и просто на девелоперских ресурсах куски кода, где запускается куча потоков (бывает что и больше 10 потоков). Но сейчас компы с 2, 4, 8, ядрами (может, и 16 есть, но их точно меньше 1%). Опять таки вопрос - в чем смысл запускать на двухъядерном проце прогу, которая создает больше 2-х потоков?
Единственная ситуация, которую я еще понимаю - это когда второй поток (тяжелый) создается для того, чтобы не подвешивать UI-поток (при этом постоянные переключения на UI-поток будут подтормаживать выполнение тяжелого потока, но по-крайней мере UI хотя бы будет реагировать на действия юзера). Но почему кучу потоков создают даже тогда, когда нет никакого UI?
Neyury: насчет моего примера с WCF не получил пока ответ. После вызова host.Open(); в программе запускается сразу 6 потоков. Для чего их столько может быть нужно, если достаточно 1 главного потока и еще 1, который будет слушать сеть? Понятно, что никаких движений мышей и т.п. библиотека WCF не должна отслеживать.
Самый простой пример в котором используется несколько потоков, это работа с сетью.
Если есть всего один поток, и он запрашивает данные из сети, то он остановит свое выполнения до момента, когда эти данные придут. Если же будет несколько потоков, то пока один ждет данные из сети, другой может спокойно продолжать работу. Помимо работы с сетью, есть еще операции чтения и записи, которые в некоторых случаях могут быть медленными.
#1
var host = new ServiceHost(typeof(AuthenticationService), serviceUri);
#2
host.Open();
#3
в точке #1 запущен 1 поток, в #2 потоков становится 2, в #3 их становится аж 6. Получается, что WCF запускает аж 6 потоков, чтобы слушать сетевой порт. Для чего он это делает, если достаточно одного потока, слушающего порт, и второго (основного) потока выполнения моей проги? Или он запускает кучу потоков не для слушания сети, а для каких-то других операций (но тогда что это могут быть за операции и есть ли вообще смысл их распараллеливать)?
да эффективность падает при переключении потоков, НО для нас важно исполнение задач именно параллельно, например ты ведешь мышкой по экрану - это отдельный процесс, который работает и должен работать параллельно.
опятьже нужно понимать что один поток не может выполняться эффективно изза задержек -> как уже упомянули одни из самых длительных задержек при обращении к сети или жесткому диску, пока данные оттуда придут, можно переключить задачу, без потери производительности.
при этом следует помнить что например поступление данных из оперативной памяти тоже имеет свои задержки, и если и пока очередная порция данных из оперативной памяти поступает, тоже можно переключиться на процесс в котором данные уже поступили и тд.
То есть, в отдельные потоки выносить имеет смысл только код, который обрабатывает данные, которые он сначала должен получить из источников, которые не управляются нашей операционной системой (и на которые не тратятся ресурсы нашего проца)? В случае с сетью все понятно - это вообще другой комп, и мы не знаем, когда он ответит. В случае с жестким диском - он читает данные данные своей вшитой микропрограммой на своем собственном микропроце и в своем собственном независимом и не принадлежащем ОС "потоке", и ОС никак не управляет тем, как он читает данные (из ОС можно только отправить диску команду "прочитай данные" и просто ждать?)? И если мы отправили команду прочитать данные жесткому диску из единственного потока, то наша прога ничего не будет делать, пока не придут данные от диска. А если мы это делаем в параллельном потоке, то в основном мы может обрабатывать другую операцию (в итоге запускать в разных потоках выгоднее).
А если предположить, что для чтения данных мы будем юзать хранилище данных, которым управляет ОС. Например, данные лежат в оперативной памяти (т.е. у нас просто в переменной объявлен гигантский массив строк string[]). Я так понимаю, оперативная память должна подойти для этого примера, потому что обращение к данным переменной происходит из нашей же ОС в том же потоке, в котором выполняется код (потому что у опер. памяти, в отличии от диска, нет своего контроллера со своим процем, ну это как я понимаю, хотя я ничего не понимаю в низкоуровневом программировании, поправьте меня тут). Если мы будем обращаться к гигантскому массиву string[] в основном потоке, то операц. система читает данные из массива в потоке нашей же программы. Допустим, все данные у нас читаются и обрабатываются 1 сек, но при этом других потоков нет, и никакие другие операции мы не делаем. Когда данные прочитались и обработались, мы запустим в том же потоке другую операцию, допустим она тоже длится 1 сек. Итого обе операции выполнятся в сумме за 2 сек. А если мы запустим чтение и обработку string[] в отдельном потоке, а вторую операцию в основном потоке, то из-за постоянных переключений потоков чтение данных из string[] будет постоянно прерываться и возобновляться, и аналогично с выполнением операции в основном потоке. В итоге все операции закончатся через те же самые 2 сек, и никакой выгоды от отдельного потока мы не получим?
То есть, если все кратко резюмировать, что я хотел спросить: если для получения данных мы тратим процессорное время своей ОС (как в случае с опер. памятью), то распараллеливать не имеет смысла (потому что общая производительность данной конфигурации компа всегда константна), а если мы тратим не ресурсы своей ОС, а чужие (как в случае с сетью или с диском), то распараллеливать имеет смысл, чтобы пока внешняя система готовит нам данные, наша система тоже выполняла какую-то работу?
Кстати, когда поток обращается к сети или диску и начинает ждать данные, то понимает ли ОС, что этому потоку не нужно выделять много проц. времени (потому что пока поток ждет данные, он ничего не будет выполнять, и ресурсы системы пропадут зря). Если система этого не понимает и выделяет одинаковое проц. время основному потоку и потоку, ждущему ответ из сети, то тогда же имеет смысл при создании потока, ждущего данные из сети, параллельно создавать максимальное кол-во потоков, которые бы выполняли полезные расчеты, потому что если есть поток, ждущий сеть, и только 1 полезный поток, то полезный поток будет использовать ресурсы системы только на 50% , а если мы создадим еще 8 полезных потоков, то полезные потоки будут использовать ресурсы системы уже на 90%. В общем, если поток тупо ждет данные из внешнего источника и не выполняет полезной работы, умеет ли система каким-то образом это определять и выделять этому потоку минимум проц. времени, а полезному потоку максимум проц. времени? Или для этого нужно использовать грязный хак "запусти больше полезных потоков - получишь больше полезной работы"?
footballer: эти все задачи давным давно очень плотно проработаны, есть пулы потоков, есть приоритеты у потоков, есть системы планировки и распределения нагрузки по потокам и тд и тому подобное.
люди тотже виндовс уже 40 лет пилят несколько десятков тысяч инженеров. Уверяю все что нужно и что бы вы могли придумать для ОС они уже реализовали)
вы откройте диспетчер задач, там обычно под сотню процессов запущенно в отдельных потоках, и все вместе они потребляют пару процентов процессорного времени.
Смысл многопоточности в многозадачности. Именно многопоточность позволяла запускать несколько приложений одновременно на одноядерном процессоре.
Не забывайте, что каждое приложение, каждая служба имеет минимум один поток. Но тем не менее даже на одноядерных процессорах можно запускать многозадачные ОС со времен 386 процессоров
Именно многопоточность позволяла запускать несколько приложений одновременно на одноядерном процессоре.
это логичнее многопроцессностью называть. А тут вопрос про то, для чего внутри 1 процесса (1 приложения) много потоков. Потому что даже если внутри всех приложений будет максимум 1 поток, то все-равно ОС позволит организовать многозадачность на одноядерном проце.