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
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.