Pull to refresh

Comments 19

Первые двух процессорные материнские платы появились в 1999 году, тогда они реально были двух процессорные — в виде двух физических камней на материнской плате

Даже если говорить только о Intel - вышедший в 1995ом Pentium Pro поддерживал двухсокетные конфигурации, соответствующие материнки появились практически сразу. На "больших" компьютерах многопроцессорные конфигурации были гораздо раньше - тут скорее надо поискать, когда появилась материнская плата в современном понимании...

хотя такая конструкция наверно и сейчас никуда не делась, где‑то применяется.

Любой современный серверный процессор поддерживает многосокетные конфигурации. "Где то" - очень слабо сказано )

изобрести концепцию multiprogramming‑а или многозадачности, которые в итоге были оформлены как концепция многопоточности

Всё таки я бы не смешивал многозадачность и многопоточность, хотя вещи действительно связаны - и то и другое вполне живо.

многопоточность, в первую очередь, предназначена для работы с аппаратными функциями внутреннего компьютерного оборудования

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

В 1962 году:

Burroughs introduces the D825 symmetrical MIMD multiprocessor. 1 to 4 CPUs access 1 to 16 memory modules using a crossbar switch. The CPUs are similar to the later B5000; the operating system is symmetrical, with a shared ready queue.

Не понял, почему статья помечена как сложная? В статье какие-то исторические справки и очевидные очевидности, не смотря на обещание в заголовке некоего практического программирования нет никаких реальных практических задач, только какой-то пример с базой данных на крошечные миллион записей, вообще нет ни одного примера, где на практике получаем большую выгоду от многозадачности, не рассмотрено ни асинхронное программирование, ни пулы потоков.

Здесь main поток запускает два потока и должен запомнить их, например в массиве

Это "не само удачное" (чтобы хуже не сказать) проектирование.

Потоки лишь метод (инструмент) обеспечения параллельного выполнения. Общепринятой практикой давно уже является создание задания - это может быть замыкание, лямбда, блок объект реализующий паттерн "команда" и так далее, то есть что-то что умеет выполняться - и у которого есть признак "завершенности".

В результате, после того, как вы уходите от парадигмы потоков к парадигме задач / вычислений, жизнь становится значительно проще и вам уже не надо "запоминать потоки, например, в массиве"

вы не могли бы привести какую-то ссылку, указать источник где можно прочитать про то что вы называете "парадигма задач / вычислений"?

@Polituraмне бы тоже было бы ужасно интересно почитать про какую-то "реальную практическую задачу" где

где на практике получаем большую выгоду от многозадачности, где применяется асинхронное программирование, пулы потоков.

Вы где-то что то подобное видели? Можете поделиться ссылкой-источником?

Я пришел к выводу что в этом направлении не существует универсальных подходов, решений, даже шаблонов проектирования. Но все упирается в конкретную схему взаимодействия потоков связанных с задачами в предметной области (параллельными -одновременными или не очень). Примеры таких схем я привел.

По схемам есть замечания? Неужели все так уж совсем просто?

@unreal_undead2 я с вами практически во всем согласен, просто хочу уточнить по поводу:

Всё таки я бы не смешивал многозадачность и многопоточность, хотя вещи действительно связаны - и то и другое вполне живо.

Я не стал их разделять потому что тогда пришлось бы погружаться в детали, которые я знаю неодназначно трактуются разными группами разработчиков, мне оно зачем?

Потом почему я их должен различать с точки зрения возможности паралелльного исполнения кусков кода или того как симулируется эта одновременность-параллельность?

Кстати, я сейчас работаю над проектом в котором мы перенесли ембедед код из модуля — приемник спуттникового радио, под Виндос на ПК. То что было задачами в ембедед стало потоками под виндой, (как тебе такое Илон Маск :) ? )

Теперь я могу дебажить Ембедед-С-код по виндусом, как будто он работает в железке, прерывания, регистры симулируются, симулируется работа внешних устройств вплоть до спуттника. Код "думает" что он работает на железке, в нем практически нет изменений для запуска в режиме библиотеки под виндосом.

Потом почему я их должен различать с точки зрения возможности паралелльного исполнения кусков кода или того как симулируется эта одновременность-параллельность?

Изначально многозадачность - это всё таки возможность выполнения независимых задач (скажем, счётные программки от Васи и Пети) на одном компьютере, и в таком виде она до сих пор живёт и к многопотоковости (как механизму, используемому прикладным программистом для использования конкурентности в своём коде) особого отношения не имеет. Да, если брать современные применения, граница достаточно нечёткая (в случаях, если мы всё таки используем несколько задач для получения общего результата), но изначальный посыл разный.

Вы где-то что то подобное видели? Можете поделиться ссылкой-источником?

Ну, постоянно по работе приходится иметь дело. Вы тоже можете убедиться в пользе многопоточности прямо не уходя с этой страницы. Просто сделайте следующее:

  1. Откройте в браузере Developer tools, для Хрома в Виндовсе это будет комбинация клавиш ctrl+shift+i, в макоси option+command+i

  2. Перейдите на закладку Network

  3. Обновите страницу.

Вы увидите, что для отрисовки этой странице было сделанно больше ста запросов (я вижу 125), там будет окошко, не знаю как называется, где показанна длительность запросов длинной палочки, ну и когда он начался и когда закончился. Большая часть палочек выполняется одновременно с другими. Количество линий, это по-сути количество потоков в пулле потоков, которому передавались задачи на выполнение загрузок. При желании вы можете прикинуть, насколько дольше бы отрисовывалась оная страничка, еслиб все эти палочки были-бы одна за другой.

Еще вариант: если у вас дискретная видеокарта, найдите ее технические характеристики, посмотрите сколько там рабочих ядер. Каждое из них медленнее ядер вашего процессора. Но многие задачи эти сотни ядер работая одновременно решают во много раз быстрее, чем их решает ваш процессор.

Упд: хотя, может я не правильно понял ваш вопрос. Вы спросили "Вы где-то что то подобное видели?", что именно вы имели ввиду? Пользу многопоточности (как я изначально понял), или асинхронное программирование, или пуллы потоков?

может я не правильно понял ваш вопрос.

Ваш комментарий в любом случае очень интересно разобрать! Поэтому это не так важно.

Интересно! Там, в вашем инструменте, есть функция посмотреть количество созданных сокетов или TCP-шных соединений?, я это вот к чему:

Польза многопоточности очевидна, когда у вас есть физическая возможность исполнять разные потоки независимо ИЛИ когда созданный поток фактически НЕ исполняется, как в случае из вашего примера с запросами. Потоки, которые привязаны к запросам (где наблюдалось 125) они ждут! То есть, фактически, ничего не делают. Вообще говоря, не факт, что это реализовано через потоки, то есть что для каждого запроса создается поток (я почти уверен что нет), потому что достаточно создать поток для одного TCP/IP соединения а все запросы по этому TCP/IP соединению отправлять по мере поступления и поддерживать привязанный к этому потоку список объектов для накопления полных ответов на отправленные запросы. Я когда то, как раз решал-рефакторил такую (примерно) задачу перехода от создания потока на каждый запрос к схеме, когда поток создается для каждого сокета(соединения), получилось:

А) намного эффективнее (проблемы прошлого решения пропали – для чего и затевался рефакторинг – новые возможности появились) и

Б) проще для реализации- компактнее, хотя возможно сложнее для понимания для кого-то,

поэтому я знаю о чем говорю. В том решении мне как раз пришлось отказаться от притянутого за уши использования пула потоков в том числе, но там все-таки задача верхнего уровня была из более узкой предметной области, чем серфинг в интернете.

Ну и когда вы ждете ответа на запрос по сети – вы ждете ответа от сетевой карты. В конечном итоге это работа с периферией, с аппаратной функцией. Это к тому, что было написано вокруг: «it was seen that at times certain processes where using peripherals (e.g.: I/O)» это прям такой случай!

 

С видеокартой пример, мне кажется, действительно уводит в сторону. То, что есть многопроцессорное железо, которое МОЖЕТ решать какие-то задачи быстрее, чем однопроцессорное железо сомнений, думаю, ни у кого нет. Хотелось бы увидеть пример такой задачи, желательно, со схемой потоков исполнения на разных процессорах. Задачи тоже есть – вы не найдете описания их реализации, тем более со схемами.

А у меня в статье еще и поднимается вопрос: а как же такие задачи работают на однопроцессорных машинах, которых, до конца 90-х, минимум, было большинство? – если коротко формулировать.

Если что, мне позволено отвечать только один раз в 24 часа. Поэтому до завтра если что! :)

Прикольно: я как та черная курица из сказки, исчезаю помаленьку :) интересные ощущения :) !

Польза многопоточности очевидна, когда у вас есть физическая возможность исполнять разные потоки независимо ИЛИ когда созданный поток фактически НЕ исполняется, как в случае из вашего примера с запросами.

На мой взгляд это все случаи и покрывает. Создавать несколько счётных потоков на однопроцессорной машине смысла нет. Просто ситуация, когда поток большую часть времени не работает на CPU, а ждёт внешнего события (скажем, пакета из сети или клика мышкой) достаточно частая

Во времена когда видеокарты были маленькими, было несколько парадигм исполнения параллельных запросов на одном(!) CPU
Можно было создавать по потоку на запрос (что в некотором смысле проще, а в некотором - сложнее)
А можно было жить в одном потоке на 'event driven' - когда из конкретного соединения вылезает часть ответа/целый ответ, вы эту часть обрабатывали и возвращались в свой select/poll/whatever.

Я это к тому, что использование потоков - необязательно, ну до тех пор пока окно браузера работает на одном CPU.

Да, у Остерхута были слайдики на эту тему - https://www.cc.gatech.edu/classes/AY2010/cs4210_fall/papers/ousterhout-threads.pdf Но не очень понятно что делать, если под рукой только синхронные API для ожидания и реагировать при этом надо на разнородные события, которые одним API типа select не покрываются.

Ну у вас либо есть WaitForMultipleObjects или какой-то смысловой аналог, либо API системы не очень годное, ну либо можно select() с микроскопическим таймаутом звать, по сути поллинг будет (тоже ничего хорошего)

Проблема, мне кажется, в том, что вот такой посыл:

под рукой только синхронные API для ожидания и реагировать при этом надо на разнородные события, которые одним API типа select не покрываются.

предполагает, что хочется найти некоторое универсальное решение для любой задачи с "разнородными событиями", асинхронными.

Но такого универсального решения НЕ существует. Решение каждой отдельной задачи с "разнородными событиями" зависит от уникальных характеристик-возможностей возникновения этих "разнородных событий”, параметров их взаимодействия. Для аналогии, мосты строятся по-разному в зависимости от геологических условий на месте, хотя снаружи выглядят как бы одинаково.

Я возьмусь утверждать, что POSIX АПИ (уже) позволяет решить любую задачу с "разнородными асинхронными событиями", просто потому что я как раз этим успешно занимался уже в самом начале 2000-х. Но каждая задача требует своего уникального решения в терминах указанного АПИ, как, впрочем, и в терминах любого другого АПИ, с подобной реализованной функциональностью.

всякие "Шпаргалка по модели памяти С++" вводят вас в заблуждения предполагая-предлагая искать универсальное решение, искать то, чего нет.

Давайте тогда конкретно. Расскажите, как в одном потоке без поллинга ждать события GUI от gtk и сетевые соединения. Я бы всё таки завёл на это отдельные потоки.

Так я не знаю в каком именно IDE мы собираемся ждать (принимать)

события GUI от gtk и сетевые соединения

Обычно IDE предоставляет некоторый способ подписки на события (любые события которые декларируются, или документируются в IDE). То есть должен быть какой-то способ передать колбек-функцию, которая будет вызвана при возникновении события. В этом случае не обязательно создавать дополнительный поток!

Я уверен что вы это знаете! Но вы хотите сфокусировать внимание на каком-то другом аспекте, но из вашего замечания мне не совсем понятно на каком, поэтому, я допускаю что вы, просто, что-то упустили из виду.

Я бы всё таки завёл на это отдельные потоки.

Возможно что я бы тоже "завёл на это отдельные потоки", но для начала я бы все таки внимательно проанализировал возможности которые предоставляет мне IDE, на предмет того, есть ли возможность "подписки" на события в каком-либо виде, и что будет эффективнее при реализации: подписка или поллинг.

Получается я опять нашел подтверждение тезису о том, что все зависит от условий конкретной задачи, мы не можем, в общем случае, решить что лучше: подписка(callback based solution) или поллинг.

в каком именно IDE

В смысле? Просто в сишном коде, зависящем только от gtk и libc.

Да просто комбинация сетки и GUI. В принципе если руками обрабатывать X11 протокол - то там те же сокеты и select() справится - но высокоуровневые библиотеки дадут свои API для ожидания событий без доступа к потрохам.

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

задача наверно хорошая, только нужно прояснить один вопрос:

у нас данные с полусотни бирж будут приходить через один Ethernet-конекшен или через пятьдесят?

Я уж не говорю о том что неплохо было бы понимать зачем к нам приходят эти данные, что мы должны с ними делать,

а то получится как в старом анекдоте:

летят Василий Иванович с Петькой в самолете.

ВИ:"Петька, приборы!"

П:"Двадцать"

ВИ:"Что двадцать?"

П:"А что приборы?"

Sign up to leave a comment.

Articles