Вопрос: Два ядра под VB6 | Добавлено: 08.08.11 21:43 |
Автор вопроса: ![]() |
Ответы | Всего ответов: 69 |
Номер ответа: 46 Автор ответа: ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Разработчик Вопросов: 130 Ответов: 6602 |
Профиль | Цитата | #46 | Добавлено: 14.08.11 04:11 |
Каддафи М пишет:
Можно, только придется в цикле (или через wait-функцию) в основном потоке ждать, когда-же function XYZ в другом потоке обработает наконец данные. Ну и зачем тут многопоточность, если одному потоку все равно приходится ждать результатов другого? |
Номер ответа: 47 Автор ответа: ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Разработчик Вопросов: 130 Ответов: 6602 |
Профиль | Цитата | #47 | Добавлено: 14.08.11 04:23 |
Объясняю на примере. C# 4.0, ибо другого не признаю.
Есть функция, которая производит некоторые вычисления. Функция полностью изолированная, принимает на вход какой-то аргумент, что-то считает, возварщает результат. Не модифицирует никаких общих ресурсов.
Функция немного читерская, так как вся нагрузка уйдет на процессор, что позволит получить хорошую масштабируемость на нескольких ядрах. Нам нужно ее посчитать для 100000 разных X. Пишем код который сгенерирует для теста значения от 0 до 100000 Пишем функцию, которая принимает 100000 аргументов, возвращает столько же результатов. Делает это в цикле, без многопоточности (кстати, многопоточность можно прикручивать только когда у тебя есть 100% рабочий однопоточный вариант. Это же касается любой оптимизации которую собираешься делать).
Теперь код который сгенерирует данные и все это запустит.
Результат выполнения - 11 секунд. Теперь прикручиваем многопоточность. Очевидно, что функция Calculate изолирована, поэтому мы можем делать одновременно несколько вычисления для разных аргументов. Кол-во потоков, которые мы запускаем, будет равно кол-ву ядер. Во-первых, это позволит максимально нагрузить все ядра процессора, во-вторых, избавит Windows Прежде всего, нужно распределить входящие данные между потоками. Есть разные способы это сделать. Например, если кол-во данных четко неизвестно, время обработки каждого элемента не постоянно, данные поступают во время работы, можно использовать producer-consumer. Но это не наш случай, мы знаем сколько данных, среднее время обработки каждого элемента будет примерно постоянным, поэтому сделаем проще. Разделим входной набор данных на несколько равных сегментов, по одному для каждого потока. |
Номер ответа: 48 Автор ответа: ![]() ![]() Вопросов: 0 Ответов: 140 |
Профиль | Цитата | #48 | Добавлено: 14.08.11 04:29 |
Вопрос не ко мне, т.к. в моих словах и был скепсис при реализации такого подхода.
Кстати, при синхронизации процессов в юзермоде можно использовать interlocked-функции. Через общую область памяти, file-mapping. |
Номер ответа: 49 Автор ответа: ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Разработчик Вопросов: 130 Ответов: 6602 |
Профиль | Цитата | #49 | Добавлено: 14.08.11 05:46 |
Рука соскочила, вобщем вот что я хотел сказать полностью.
Объясняю на примере. C# 4.0, ибо другого не признаю. Есть функция, которая производит некоторые вычисления. Функция полностью изолированная, принимает на вход какой-то аргумент, что-то считает, возварщает результат. Не модифицирует никаких общих ресурсов.
Функция немного читерская, так как вся нагрузка уйдет на процессор, что позволит получить хорошую масштабируемость на нескольких ядрах. Нам нужно ее посчитать для 100000 разных X. Пишем код который сгенерирует для теста значения от 0 до 100000 Пишем функцию, которая принимает 100000 аргументов, возвращает столько же результатов. Делает это в цикле, без многопоточности (кстати, многопоточность можно прикручивать только когда у тебя есть 100% рабочий однопоточный вариант. Это же касается любой оптимизации которую собираешься делать).
Теперь код который сгенерирует данные и все это запустит.
Результат выполнения - 11 секунд. Теперь прикручиваем многопоточность. Очевидно, что функция Calculate изолирована, поэтому мы можем делать одновременно несколько вычисления для разных аргументов. Кол-во потоков, которые мы запускаем, будет равно кол-ву ядер. Во-первых, это позволит максимально нагрузить все ядра процессора, во-вторых, избавит Windows от необходимости часто переключать контексты. Прежде всего, нужно распределить входящие данные между потоками. Есть разные способы это сделать. Например, если кол-во данных четко неизвестно, время обработки каждого элемента не постоянно, данные поступают во время работы, можно использовать producer-consumer. Но это не наш случай, мы знаем сколько данных, среднее время обработки каждого элемента будет примерно постоянным, поэтому сделаем проще. Разделим входной набор данных на несколько равных сегментов, по одному для каждого потока.
Проверка для последнего сегмента стоит для того, чтоб в случае когда кол-во элементов не делится поровну на кол-во потоков не осталось в конце пропущенных элементов, которые не попали ни в один сегмент. Пишем функцию, которая будет делать рассчет результатов для сегмента. В отличие от других, она не будет возвращать результат с массивом. Она принимает в качестве агрумента этот массив и записывает в него результаты вычислений. Делаем так, чтоб после работы не пришлось собирать в кучу несколько массивов.
Теперь остается добавить код запуска потоков.
Как видим, основной поток не выполняет никаких вычислений, он только запускает несколько рабочих потоков, которые и выполнят основную работу. Здесь есть большая проблема - основной поток вернет результат сразу после того как запустит потоки. В этот момент результатов еще никаких не будет. Поэтому нужно сначала дождаться пока потоки отработают, только после этого делать return. Для этого используем синхронизацию на основе массива ManualResetEvent
Результат выполнения - 6.3 секунды. Т.е. в 1.8 раза быстрее (на двухъядерном компьютере). Если запустить на 4-ядерном компьютере (с поддержков HT, т.е. 8 логических ядер, далее называю его 8-ядерным), получим 11.16 секунд и 1.52 секунды - в 7.3 раза быстрее. Вот то же самое на TPL
Результат работы - 6.6 секунд на двухъядерном, 1.53 на 8-ядерном. Видны небольшие накладные расходы у TPL. Вариант на PLinQ (это тоже TPL, но немного другой подход)
7 секунд на двухъядерном, 2 секунды на 8-ядерном ======================================================================== Как видишь, никаких приоритетов и масок здесь не нужно. Нужно, тем не менее, понимать что происходит Например, мой первый вариант повис после 3-го запуска. Оказалось, причина была в этом
Чтоб легко передать в поток параметры я использовал lambda выражение. И получил типичную гонку потоков. В тот момент, когда lambda выражение выполнялось переменная t успевала увеличиться на 1. И в оба потока попадал один и тот же manualResetEvent. Потоки его сбрасывали, но первый ManualResetEvent оставался заблокированным и функция продолжала висеть. С таким же успехом я мог получить что-то вроде ArgumnetOutOfrRangeException, если бы это происходило не при запуске первого потока, а при запуске второго. В конце цикла t увеличивается на 1, становится равной 2 и цикл завершается. После этого lambda выражение пытается считать из массива event'ов элемент по индексу 2, которого, раузмеется не существует (всего 2 элемента, индексация с 0). TPL дает небольшое проседание скорости, но избавляет от необходимости решать многие задачи. Моя задача очень хорошо распараллелилась. Во-первых потому что я почти не работаю с памятью. Во-вторых, потому что результаты я считываю и записываю и разных сегментов массива. Очевидно, что каждый сегмент попал в кеш того ядра, которое его обрабатывает и не было необходимости тратить время на синхронизацию доступа к общему участку памяти. Можно написать программу, которая, как кажется, не модифицирует общую память, тем не менее, в реальности окажется, что она модифицирует участки памяти, лежащие рядом, и полностью попадающие в кеш того или иного ядра, остальным прийдется работать намного менее эфективно, поскольку модификация данных, которые лежат в кеше другого ядра займет много времени. |
Номер ответа: 50 Автор ответа: ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Разработчик Вопросов: 130 Ответов: 6602 |
Профиль | Цитата | #50 | Добавлено: 14.08.11 05:49 |
Да, остерегайся багов в этом коде. Писал на скорую руку, мог что-то упустить. Вижу что у меня уже сегменты перекрываются, но вобщем это только иллюстрация идеи, а не руководство к действию. |
Номер ответа: 51 Автор ответа: ![]() ![]() ![]() ![]() ![]() ICQ: adamis@list.ru Вопросов: 153 Ответов: 3632 |
Профиль | Цитата | #51 | Добавлено: 14.08.11 06:36 |
Artyom пишет:
что механизмы синхронизации режима ядра относительно медленные собсно эти тормоза я и имел ввиду, хотя мне далеко конечно до вашего уровня |
Номер ответа: 52 Автор ответа: ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Вопросов: 8 Ответов: 81 |
Профиль | Цитата | #52 | Добавлено: 14.08.11 07:45 |
На каком ядре какой поток запускать - это задача которую решает планировщик. Причем он не будет четко разделять - один поток на одном ядре, другой на другом, а будет условно случайным образам выдавать им кванты времени, Т.е. в среднем поток половину времени проработает на первом ядре, половину на втором. То же самое если потоков будет 10.
Как сейчас модно говорить – звезда в шоке. Теперь я окончательно не понимаю зачем нужна многопоточность. Если все равно планировщик будет выдавать потокам кванты времени, то получается, что различия во времени выполнения программы, если она работает в одном потоке или в двух потоках, не будет. Просто планировщик выделит больше квантов времени для работы на двух ядрах критичному по времени выполнения потоку (если их два) или выделит в сумме столько же квантов времени, если задача решается в одном потоке. С наилучшими пожеланиями Сергей Юдин. |
Номер ответа: 53 Автор ответа: ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Вопросов: 8 Ответов: 81 |
Профиль | Цитата | #53 | Добавлено: 14.08.11 13:49 |
Объясняю на примере. C# 4.0, ибо другого не признаю.
А я считаю это не объяснением, а натуральным очковтирательством, т.к. Ваш пример не объясняет преимуществ многопоточности, а показывает, что 4-е землекопа выроют траншею в 4-е раза быстрее, чем один. С таким же успехом Ваш пример можно реализовать на 4-х разных компьютерах по 25000 слагаемых, а потом результаты просуммировать столбиком или на одном и том же компьютере 4-раза по 25000. Причем код бы в этом случае был самый примитивный и даже с затратой времени на сложение столбиком общие затраты времени в этом случае были бы на несколько порядков меньше, чем в Вашем варианте. Мне кажется, что, создавая многоядерные компьютеры, их разработчики хотели хотя бы частично устранить основной недостаток цифровых компьютеров, а именно последовательность вычислений. Ведь аналоговые компьютеры (сейчас остались известны только нейрокомпьютеры) производят параллельные во времени вычисления всех процессов протекающих в рассматриваемом явление природы или социальном феномене. И разработчики, быстрее всего, заложили в них эту возможность (вот только мы не сообразим, как ее реализовать). С наилучшими пожеланиями Сергей Юдин. |
Номер ответа: 54 Автор ответа: ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Разработчик Вопросов: 130 Ответов: 6602 |
Профиль | Цитата | #54 | Добавлено: 14.08.11 14:18 |
А зачем ты пришел на форум спрашивать про многопоточность если ты считаешь что уже и так знаешь как там все работает?
Причем, судя по тому что ты пишешь ты вообще не имеешь ни малейшего представления об этом. Не хочу тебя расстраивать, но суть именно в том что 4 землекопа выроют траншею в 4 раза быстрее. Причем в идеальном случае. Если им прийдется при этом постоянно согласовывать свои действия, ждать пока один человек на тележке вывозит землю, и у них будет 2 лопаты на 4-х, то в 4 раза быстрее они траншею не выкопают. Сергей Юдин пишет:
С таким же успехом Ваш пример можно реализовать на 4-х разных компьютерах по 25000 слагаемых, а потом результаты просуммировать столбиком или на одном и том же компьютере 4-раза по 25000. Это следующий этап. При этом существенно возрастают затраты на коммуникацию между процессами. Поэтому при масштабировании на несколько компьютеров нужно приложить больше усилий, чтоб минимизировать необходимость процесов взаимодействовать друг с другом. Собственно по такому принципу работает map-reduce. В гугле, например. Только вместо 4 компьютеров используется несколько тысяч. Сергей Юдин пишет:
Причем код бы в этом случае был самый примитивный и даже с затратой времени на сложение столбиком общие затраты времени в этом случае были бы на несколько порядков меньше, чем в Вашем варианте. Что за ерунду ты говоришь? Я просто написал функцию, которая грузит процессор и работает некоторое время. Понятное дело что можно посчитать все формулой прогрессии и т.п. Я не буду тратить время на то чтоб тебе сделать пример с матаном. Функцию сам пиши, какую тебе надо. Сергей Юдин пишет:
Мне кажется, что, создавая многоядерные компьютеры, их разработчики хотели хотя бы частично устранить основной недостаток цифровых компьютеров, а именно последовательность вычислений. Ведь аналоговые компьютеры (сейчас остались известны только нейрокомпьютеры) производят параллельные во времени вычисления всех процессов протекающих в рассматриваемом явление природы или социальном феномене. И разработчики, быстрее всего, заложили в них эту возможность (вот только мы не сообразим, как ее реализовать). Когда кажется - креститься нужно. Я тебе описываю не то что кажется, и не то что хотели, а то как это есть на самом деле. |
Номер ответа: 55 Автор ответа: ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Разработчик Вопросов: 130 Ответов: 6602 |
Профиль | Цитата | #55 | Добавлено: 14.08.11 14:25 |
Если твою задачу нельзя распараллелить (т.е. одна операция всегда зависит от операций, которые выполнялись перед ней), то ты никакой многопоточности не сможешь сделать. И многоядерный процессор не даст преимуществ перед одноядерным (не считая преимущества за счет того что почти все одноядерные процессоры морально устарели по сравнению с современными многоядерными, и даже одно ядро многоядерного процессора будет работать существенно быстрее).
Если на входе есть большой массив данных и для каждого элемента массива нужно произвести одинаковые вычисления, то задача будет параллелиться отлично. Видеокарты, например, именно так и работают, параллельно производя одни и те же рассчеты для каджого пиксела. Только ядер там существенно больше - несколько сотен. Собственно математики этим и пользуются, перенося рассчеты на видеокарту, или специально созданное для этого устрйоство (у NVIDIA есть такие). |
Номер ответа: 56 Автор ответа: ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Вопросов: 8 Ответов: 81 |
Профиль | Цитата | #56 | Добавлено: 14.08.11 19:26 |
А зачем ты пришел на форум спрашивать про многопоточность если ты считаешь что уже и так знаешь как там все работает?
Причем, судя по тому что ты пишешь ты вообще не имеешь ни малейшего представления об этом. Я пришел, чтобы оптимизировать решение своей задачи, а не потрепаться на общие темы и показать какой я умный или выслушивать какой я глупый и рассматривать пример, который никакого отношения не имеет к моей задаче. Кстати, два потока я запускал лет 8 назад и в конкретной своей задаче, а не в абстрактном примере. А вот ты Юпитер сердишься, значит ты не прав. Без пожеланий Сергей Юдин. |
Номер ответа: 57 Автор ответа: ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Вопросов: 8 Ответов: 81 |
Профиль | Цитата | #57 | Добавлено: 15.08.11 06:18 |
А зачем ты пришел на форум спрашивать про многопоточность если ты считаешь что уже и так знаешь как там все работает?
Причем, судя по тому что ты пишешь ты вообще не имеешь ни малейшего представления об этом. Я пришел, чтобы оптимизировать решение своей задачи, а не потрепаться на общие темы и показать какой я умный или выслушивать какой я глупый и рассматривать пример, который никакого отношения не имеет к моей задаче. Кстати, второй поток (правда, простейший) я запускал еще лет 6 назад и в конкретной своей задаче, а не в абстрактном примере. А вот ты Юпитер сердишься, значит, ты не прав (даже, если окажется, что ты был прав по поводу чисто экстенсивного пути развития современных цифровых компьютеров). Без пожеланий Сергей Юдин. |
Номер ответа: 58 Автор ответа: ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Разработчик Вопросов: 130 Ответов: 6602 |
Профиль | Цитата | #58 | Добавлено: 15.08.11 08:31 |
Ты ждешь что здесь кто-то тебе будет писать пример под твою конкретную задачу? Чтоб ты просто скопипастил код в свой проект? Тебе тогда нужно было отправляться на freelance.ru
Повторяю последний раз, любая задача решается также. Задача разбивается на подзадачи, которые можно выполнять параллельно. Эти подзадачи выполняются параллельно, после этого результаты работы агрегируются и выдаются. Мои знания получены из заслуживающих доверия источников (Рихтер, Руссинович, Тауб) и на основе личного опыта и пока сомнению не подлежат, по крайней мере кроме тебя еще никто не начал кричать что в интернете кто-то не прав ![]() |
Номер ответа: 59 Автор ответа: ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Вопросов: 8 Ответов: 81 |
Профиль | Цитата | #59 | Добавлено: 15.08.11 22:36 |
Ты ждешь что здесь кто-то тебе будет писать пример под твою конкретную задачу? Чтоб ты просто скопипастил код в свой проект? Тебе тогда нужно было отправляться на freelance.ru
Мои знания получены из заслуживающих доверия источников (Рихтер, Руссинович, Тауб) и на основе личного опыта и пока сомнению не подлежат, по крайней мере кроме тебя еще никто не начал кричать что в интернете кто-то не прав ![]() Слушай знахарь, хватит ТЫкать, т.к. мои познания по вопросам мироздания получены мною лично, а не из книжек. А программированием (по необходимости) я начал заниматься более 30 лет тому назад и работал на ЭВМ, когда у них еще не было ни дисплея, ни клавиатуры, т.е. насмотрелся на своем веку всяких великих ученых и в том числе по программированию. И если я усомнился в твоих познаниях, то это еще не значит, что ТЫ не прав. Возможно, действительно, создатели цифровых компьютеров уперлись в стену дальнейшего их прогресса, и пошли по чисто экстенсивному пути их развития, который не позволяет решать нам 99% реальных задач. На квантовый компьютер можешь не рассчитывать, т.к. мои познания квантовой механики позволяют заявить, что он не будет создан никогда. Аналоговые ЭВМ и нейрокомпьютеры хороши тем, что решают всю задачу за один проход множеством потоков, но в аналоговых сложно подобрать схему и промасштабировать его элементы, а в нейрокомпьютере трудно понять, почему получился такой результат. По этому, я и ожидал от многоядерных компьютеров прогресса именно в параллельности решения 99% задач, которые стоят перед нами, а не повышения мощности //однопоточного// компьютера при разбиение однопоточной задачи на части, не зависящие друг от друга, за счет увеличения ядер, т.к. тактовую частоту повышать дальше нельзя. А по поводу первого вопроса, то вообще то я не надеялся, что кто-то займется конкретно моей задачей (хотя раньше таких прецедентов было много и я не очень удивлялся этому), но сейчас думаю, что это было бы не плохо, т.к. человек, занявшийся этим и, если бы у него это получилось, внес бы большой вклад в развитие науки, т.к. все наши научные задачи решаются именно так, как моя задача. А сейчас (последние три года) я занимаюсь поиском скорости распространения гравитации. Если все получится, то это будет окончательно означать, что Эйнштейн мошенник, т.к. пока это доказывается только опосредованно. Я считаю, что решаемая задача стоит и времени и сил, т.к. результат стоит того. Так что поумерьте свою гордыню, а если у ВАС это получится, то я не держу на ТЕБЯ обиду и ради большого дела готов согласиться на помощь в решение этой задачи. По прежнему без пожеланий Сергей Юдин. |
Номер ответа: 60 Автор ответа: ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Разработчик Вопросов: 130 Ответов: 6602 |
Профиль | Цитата | #60 | Добавлено: 15.08.11 23:07 |
Если в интернете кто-то не прав, я это говорю. Вне зависимости от того сколько этот кто-то занимается программированием.
То что вас интерисует работает так как я описал. Спросите у любого другого специалиста, он повторит вам то же самое. И обвинять меня в чем-то только потому что вам хотелось чтоб все работало по другому очень глупо, не кажется? Сергей Юдин пишет:
А по поводу первого вопроса, то вообще то я не надеялся, что кто-то займется конкретно моей задачей (хотя раньше таких прецедентов было много и я не очень удивлялся этому), но сейчас думаю, что это было бы не плохо, т.к. человек, занявшийся этим и, если бы у него это получилось, внес бы большой вклад в развитие науки, т.к. все наши научные задачи решаются именно так, как моя задача. А сейчас (последние три года) я занимаюсь поиском скорости распространения гравитации. Если все получится, то это будет окончательно означать, что Эйнштейн мошенник, т.к. пока это доказывается только опосредованно. Я считаю, что решаемая задача стоит и времени и сил, т.к. результат стоит того. Так что поумерьте свою гордыню, а если у ВАС это получится, то я не держу на ТЕБЯ обиду и ради большого дела готов согласиться на помощь в решение этой задачи. Ну так в чем проблема тогда? Наймите специалиста который разбирается в матанализе и параллельном программировании, и двигайте науку. |
|