Название: multi-threading porting Отправлено: Igors от Август 26, 2012, 13:50 Добрый день
Нужно "разпоточить" задачу которая изначально была написана без всякого учета multi-threaded. Певдокод Код Как это приспособить для выполнения 2-мя или более нитками. учитывая что вызовы SetupCube обычно съедают намного больше половины времени выполнения? Спасибо Название: Re: multi-threading porting Отправлено: LisandreL от Август 26, 2012, 14:08 Смотря что SetupCube делает.
OpenMP тут не срабатывает? Название: Re: multi-threading porting Отправлено: Igors от Август 26, 2012, 14:19 Смотря что SetupCube делает. SetupCube заполняет содержимое CCube генерируя случайные данные (seed привязан к аргументам). OpenMP конечно срабатывает, но не делает метод thread-safeOpenMP тут не срабатывает? Название: Re: multi-threading porting Отправлено: Serr500 от Август 26, 2012, 17:19 SetupCube влияет на весь массив mCube или только на элемент, который в неё передаётся?
Название: Re: multi-threading porting Отправлено: Igors от Август 26, 2012, 17:37 SetupCube влияет на весь массив mCube или только на элемент, который в неё передаётся? Только на элемент, но вызывается для всех 9 кубов (27 в оригинале)Название: Re: multi-threading porting Отправлено: Serr500 от Август 26, 2012, 18:09 Ну, если предположить, что SetupCube не только не влияет на иные элементы mCube, но и не использует их, то все вызовы SetupCube оказываются независимыми:
Код: i j (j + 1) * 3 + i + 1 Код: for (int i = -1; i <= +1; ++i) Название: Re: multi-threading porting Отправлено: Igors от Август 26, 2012, 18:18 Поэтому можно выполнять каждое вычисление независимо в отдельном потоке. Запуск неприемлем - он съест больше времени чем само SetupCube. Да, основное время съедается именно на SetupCube, но за счет хорошей кратности DoCalc (миллионы)Название: Re: multi-threading porting Отправлено: Serr500 от Август 26, 2012, 18:29 Тогда я чего-то не понимаю. Надо сделать DoCalc многопоточным внутри или сделать DoCalc thread-safe, чтобы его безопасно было запускать из разных потоков?
Название: Re: multi-threading porting Отправлено: Igors от Август 26, 2012, 18:34 Тогда я чего-то не понимаю. Надо сделать DoCalc многопоточным внутри или сделать DoCalc thread-safe, чтобы его безопасно было запускать из разных потоков? Делать thread-safeНазвание: Re: multi-threading porting Отправлено: Serr500 от Август 26, 2012, 18:47 Тогда, к примеру, так:
Код: class CData Название: Re: multi-threading porting Отправлено: Igors от Август 26, 2012, 19:00 Тогда, к примеру, так: А Вас не смутило что это уж слишком очевидно? Так конечно thread-safe, но на 4-х ядрах это работает в неск раз медленне чем на одном.От бывшего математика я ожидал большего :'( Название: Re: multi-threading porting Отправлено: Serr500 от Август 26, 2012, 19:15 А Вас не смутило что это уж слишком очевидно? Вообще-то смутило... У меня до сих пор стойкое ощущение, что я чего-то не понял...Так конечно thread-safe, но на 4-х ядрах это работает в неск раз медленне Это меня удивляет. Замедление, конечно, возникает, но не до такой же степени. Может, надо ещё и вызывающий код оптимизировать?От бывшего математика я ожидал большего :'( Так ведь бывший... :'( :'( :'(Хорошо, вот ещё одна идея. Создавать при начале выполнения программы несколько потоков (по числу ядер), ставить на паузу. Каждый поток должен будет выполнять SetupCube. Но после завершения вычислений не завершать работу, а приостанавливаться (например, на мьютексе). После инициализации переменных мьютекс разблокируется и поток выполняет вычисление. Пауза на мьютексе намного "легче", чем пересоздание потока. Если пофиг загрузка процессора, то можно сделать даже спин-блокировку, тогда реагировать на снятие с паузы поток будет почти моментально. Название: Re: multi-threading porting Отправлено: Igors от Август 26, 2012, 19:31 Это меня удивляет. Замедление, конечно, возникает, но не до такой же степени. Ничего удивительного. На одной нитке трудоемкие вызовы SetupCube в 90% успешно пропускаются, а на 4-х каждая прется со своими x, y которых ничего общего. Ну и все уходит в SetupCube как вода в песок. Хорошо, вот ещё одна идея. Создавать при начале выполнения программы несколько потоков (по числу ядер), ставить на паузу. Каждый поток должен будет выполнять SetupCube. Но после завершения вычислений не завершать работу, а приостанавливаться (например, на мьютексе). После инициализации переменных мьютекс разблокируется и поток выполняет вычисление. Пауза на мьютексе намного "легче", чем пересоздание потока. Если пофиг загрузка процессора, то можно сделать даже спин-блокировку, тогда реагировать на снятие с паузы поток будет почти моментально. Создание "бригады ниток" не вопрос, также как и натравить ее на что-то. В OpenMP делается напр такКод Однако даже такой (пере) запуск имеет смысл на приличном size() или DoCalc. А запускать бригаду на 9 вызовов SetupCube - в минус. Ну и потом - посчитанные кубы используются в DoCalc до его завершения. Название: Re: multi-threading porting Отправлено: LisandreL от Август 27, 2012, 08:34 Запуск неприемлем - он съест больше времени чем само SetupCube. Да, основное время съедается именно на SetupCube, но за счет хорошей кратности DoCalc (миллионы) Ну, тогда моё неэкспертное мнение:распараллеливать там, где вызывается DoCalc эти миллионы раз 1) Если данные и обработка независимы, то всё хорошо, но я думаю при этом вопросов у вас не возникло бы. 2) Если DoSomethingWithCubes(mCube); обращается к общим ресурсам, но не важен порядок его вызова то можно попробовать прикрыть его или его части мьютексами/критическими секциями/атомарными операциями. При условии, что дольше работает SetupCube - есть шанс получить profit. Поиграться с числом потоков. Учитывая, что некоторые потоки будут стоять в мьютексах есть вероятность того, что оптимальное их число будет несколько больше количества ядер. 3) Если важен порядок вызова, то выделить генерацию данных (вызовы SetupCube) и параллелить их, а уже DoSomethingWithCubes(mCube);... выполнять в один поток, когда данные сгенерированы (более сложный вариант - по мере генерации данных). Но это всё просто идеи, применимость которых, не представляя проект, я оценить не могу. Вполне допускаю, что, например, с распараллеливанием вызовов DoCalc могут быть трудности. Название: Re: multi-threading porting Отправлено: Igors от Август 27, 2012, 09:06 Но это всё просто идеи, применимость которых, не представляя проект, я оценить не могу. Вполне допускаю, что, например, с распараллеливанием вызовов DoCalc могут быть трудности. Собственно DoCalc и параллелится, т.е. вызывается многими нитками с разными аргументами. Это просто плагин, процедуральная текстура (ну можно сказать фрактал). Метод DoCalc вызывается хостом, когда хост сочтет нужным, обычно очень много раз. В связи с тем что хост стал multi-threaded необходимо сделать этот метод thead-safe - в том виде как сейчас он рухнет. Простое решение Код: // if (ix != mX || iy != mY) { Название: Re: multi-threading porting Отправлено: vregess от Август 30, 2012, 14:58 Я, может, тоже не совсем понял задачу.
Не совсем понятны эти троеточия в CData, как там все связано. Ну раз видно только mCube, DoCalc(), SetupCube(), DoSomethingWithCubes(), значит методы выполняются последовательно, и извне не используются SetupCube() и DoSomethingWithCubes(), наверное хост будет юзать mCube после этих вычислений. Почему бы не выделить это все в отдельный воркер и помещать его в пулл потоков для вычислений. Псевдокод (очень упрощенно): Код
Те хост говорит начать вычисления и ловит сигнал окончания, потом использует. Если нужно выполнить синхронно, то указываем дополнительные параметры в connect(). Если нет, то пулл должен организовывать очередь запросов, если все потоки заняты. В принципе мы тут не используем всякие блокировки напрямую - все делает фреймворк (вопрос, насколько оптимально). Не могу сказать, сколько займет процесс подготовки воркера (перемещение в поток и вызов слота doCalc). Вот такая вот идея. PS Забавно, об этом топике узнал из эпического "Нежелание новичков изучать документацию", похоже "показать новые сообщения" работает избирательно :) Название: Re: multi-threading porting Отправлено: Igors от Август 30, 2012, 16:37 Не совсем понятны эти троеточия в CData, как там все связано. Ну раз видно только mCube, DoCalc(), SetupCube(), DoSomethingWithCubes(), значит методы выполняются последовательно, и извне не используются SetupCube() и DoSomethingWithCubes(), наверное хост будет юзать mCube после этих вычислений. Не будет. Если бы какие-то данные использовались совместно/shared - я обязан был бы упомянуть. А так Вы совершенно правильно полагаете что хосту известно только DoCalc и ничего более (про mCube он тоже ничего не знает). Поэтому сигналы здесь не нужны.Название: Re: multi-threading porting Отправлено: vregess от Август 30, 2012, 17:25 Не будет. Если бы какие-то данные использовались совместно/shared - я обязан был бы упомянуть. А так Вы совершенно правильно полагаете что хосту известно только DoCalc и ничего более (про mCube он тоже ничего не знает). Поэтому сигналы здесь не нужны. Тогда не понятно, что нужно получить. То, что надо выполнять DoCalc() безопасно для данных CData, ни о чем особо не говорит (вторая страница догадок :)). Слишком мало информации. Название: Re: multi-threading porting Отправлено: Igors от Август 30, 2012, 18:46 Тогда не понятно, что нужно получить. Как раз о всем и говорит. Выполнять его безопасно надо - как есть он просто загнется. А "просто залочить" - позорный провал по скорости (см. обсуждение выше).То, что надо выполнять DoCalc() безопасно для данных CData, ни о чем особо не говорит (вторая страница догадок :)). Как это приспособить для выполнения 2-мя или более нитками. учитывая что вызовы SetupCube обычно съедают намного больше половины времени выполнения? Что не так, неясно и зачем включать непонятку? :) |