LINUX.ORG.RU

Автоматический параллелизм


0

0
Программирую на Схеме. Пишу следующую функцию

(define (int a b f)
    (if (< (abs (- b a)) eps)
         (* (f (mid-point a b)) (- b a))
         (+ (int a (mid-point a b) f) (int (mid-point a b) b f))))

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

Можно ли (директивами или как еще) заставить guile использовать
несколько вычислительных потоков?
Проблема в том, что схема -- не чисто функциональный язык, и вызов функции может иметь какие-нибудь побочные эффекты. Поэтому схема сама ничего и не паралелит, ибо она не может тебе доверять, вдруг вызов mid-point у тебя завязан на глобальную переменную, которую он еще и меняет через set! к тому же ;) Автоматическое распараллеливание при этом раскладе приведет к хаосу
swizard
()
Ответ на: комментарий от swizard
Не, я это более-менее понимаю. Вопрос состоит в том, могу ли я сказать интерпретатору "зуб даю, тут все безопасно", а он, соответственно, все распараллелит?
annoynimous ★★★★★
() автор топика
Ответ на: комментарий от annoynimous
На самом деле, не такое это простое действие, как ты думаешь :)
Если ты хочешь прозрачности, то в твоем конкретном случае, можно
написать простенький макрос вида (define-macro (force-multithread expr) ...),
который для s-выражения вида (proc arg0 arg1 .. argn) явно форкает по
треду на каждый аргумент, ждет результатов и передает их proc.

Соответственно, должно получится что-то типа
(define (int a b f)
  (if (< (abs (- b a)) eps)
     (* (f (mid-point a b)) (- b a))
     (force-multithread (+ (int a (mid-point a b) f) (int (mid-point a b) b f)))))

Проблема в том, что, во-первых, такой подход не прокатит для хвостовых рекурсий (вообще я сомневаюсь, что цикл можно грамотно распараллелить в общем случае), и, во-вторых, для глубокой рекурсии у тебя нафоркается слишком много нитей.
swizard
()
Автоматизация паралеллизма сложная задача. Во всех реализациях нужна явная аннотация (указание) на то, что нужно распараллеливать.
Kpoxman ★★
()
Ответ на: комментарий от swizard
> во-вторых, для глубокой рекурсии у тебя нафоркается слишком много нитей.

Щас, пока шел домой, подумал... Можно ж держать глобальный пул тредов, не форкая больше, чем какая-нибудь заданная константа. Да и родительскому треду необязательно висеть в ожидании, он сам может посчитать какой-нибудь аргумент :)

Вообще, симпатичная идея с этим force-multithread получается... Можно даже какой-нибудь чисто-функциональный scheme-like интерпретатор реализовать, где мутаторы запрещены, и распараллеливание делается автоматически...

swizard
()
Ответ на: комментарий от swizard
Ага, вот только, сколько вы заплатите за создание нити? Или будете делать свою реализацию, как в Erlang?
krum
()
Ответ на: комментарий от krum
> Ага, вот только, сколько вы заплатите за создание нити? > Или будете делать свою реализацию, как в Erlang?

Ну можно заранее нафоркать тредов, и свободным передавать continuations... Только тут даже не в этом дело -- скорее всего будет гемор с ресурсами, типа файлов, сокетов и прочее... Там такого можно автоматически напараллелить, что потом хрен поймешь что и где :)

swizard
()
Ответ на: комментарий от swizard
Тогда почитайте про Haskell:) Там как раз эту проблему решили, как в чистом функциональном языке быть с сокетами, файлами и тд.
krum
()
Ответ на: комментарий от krum
Никак не могу осилить монады :) Все маны по ним идут с примерами на хаскеле, а я в нем пока ничерта не соображаю =) Неужели они больше нигде не применяются?
swizard
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.