Поддерживает ли Forth многопоточность?
Некоторое время я немного взглянул на язык программирования Forth. Можно ли сделать многопоточность с примитивами синхронизации в Forth?
Например, возможно ли сделать матричное умножение n на n с несколькими потоками в Forth? Если да, то каков основной механизм или шаблоны программирования?
3 ответа
Для заявленной цели многопоточность должна быть преимущественной. В Simple Forths есть цикл задач PAUSE, который запускает задачи одну за другой, не перекрывая друг друга. Удивительно полезно, но не в этом случае.
Современный, профессиональный, Forth может выполнять многопоточность, но я знаю только один со специальными примитивами, чтобы сделать его проще.
Приведенный выше пример умножения матриц не является демонстрацией многопоточности.
Насколько мне известно (*), только компилятор iForth имеет специальные многопоточные примитивы (на основе OCCAM) и поставляется с примерами, которые действительно работают в x раз быстрее на n-ядерных процессорах (где x Для матриц 1024 x 1024 это (mmul2) примерно в два раза быстрее, чем однопоточная версия (mmul1). (*) Ходят слухи, что MPE и Forth Inc недавно добавили похожую функциональность.0 VALUE jj
: mmul2 ( F: -- r )
a3 /size DFLOATS ERASE
/rsz 0 DO
I TO jj
PAR
STARTP /rsz 0 DO a1 jj /rsz * I + DFLOAT[] DF@ a2 I /rsz * DFLOAT[] a3 jj /rsz * DFLOAT[] /rsz DAXPY_sse2 LOOP ENDP
STARTP /rsz 0 DO a1 jj 1+ /rsz * I + DFLOAT[] DF@ a2 I /rsz * DFLOAT[] a3 jj 1+ /rsz * DFLOAT[] /rsz DAXPY_sse2 LOOP ENDP
STARTP /rsz 0 DO a1 jj 2+ /rsz * I + DFLOAT[] DF@ a2 I /rsz * DFLOAT[] a3 jj 2+ /rsz * DFLOAT[] /rsz DAXPY_sse2 LOOP ENDP
STARTP /rsz 0 DO a1 jj 3 + /rsz * I + DFLOAT[] DF@ a2 I /rsz * DFLOAT[] a3 jj 3 + /rsz * DFLOAT[] /rsz DAXPY_sse2 LOOP ENDP
STARTP /rsz 0 DO a1 jj 4 + /rsz * I + DFLOAT[] DF@ a2 I /rsz * DFLOAT[] a3 jj 4 + /rsz * DFLOAT[] /rsz DAXPY_sse2 LOOP ENDP
STARTP /rsz 0 DO a1 jj 5 + /rsz * I + DFLOAT[] DF@ a2 I /rsz * DFLOAT[] a3 jj 5 + /rsz * DFLOAT[] /rsz DAXPY_sse2 LOOP ENDP
STARTP /rsz 0 DO a1 jj 6 + /rsz * I + DFLOAT[] DF@ a2 I /rsz * DFLOAT[] a3 jj 6 + /rsz * DFLOAT[] /rsz DAXPY_sse2 LOOP ENDP
STARTP /rsz 0 DO a1 jj 7 + /rsz * I + DFLOAT[] DF@ a2 I /rsz * DFLOAT[] a3 jj 7 + /rsz * DFLOAT[] /rsz DAXPY_sse2 LOOP ENDP
ENDPAR
8 +LOOP
0e a3 /size 0 ?DO DF@+ F+ LOOP DROP ;
FORTH> TESTS
DOT/AXPY using 64 bits floats.
Vector size = 1048576
mul0 (dot) : 6.8719411200000000000e+0013 0.133 seconds elapsed.
mul1 (dot_sse2) : 6.8719411200000000000e+0013 0.106 seconds elapsed.
mmul0 (axpy) : 5.6294941655040000004e+0014 0.981 seconds elapsed.
mmul1 (axpy_sse2) : 5.6294941655040000004e+0014 0.400 seconds elapsed.
mmul2 (Paxpy_sse2) : 5.6294941655040000004e+0014 0.114 seconds elapsed. ok
Любой Forth, который может сделать многозадачность, может сделать многопоточность также. (Это одно и то же в приложении.) Почти все Форты могут сделать это сейчас.
Вы можете сделать что-то вроде:
include fsl-util.f
3 3 float matrix A{{
A{{ 3 3 }}fread 1e 2e 3e 4e 5e 6e 7e 8e 9e
3 3 float matrix B{{
B{{ 3 3 }}fread 3e 3e 3e 2e 2e 2e 1e 1e 1e
3 3 float matrix C{{ \ result
A{{ B{{ C{{ mat*
C{{ }}print
На данный момент стандарт Forth не определяет слова, относящиеся к многопоточности или многозадачности. Хотя многие исторические реализации Forth имеют такие примитивы или позволяют определять их, используя Forth-ассемблер или API для базовой системы.
Например, примитивы синхронизации и многопоточность в SP-Forth/4 в основном представляют собой просто обертки над API Windows и Linux (pthreads).
Обратите внимание, что пул потоков должен использоваться для повышения производительности для небольших операций - поскольку создание / уничтожение потока может быть трудоемкой операцией.
Также возможно, что реализация умножения матриц n-на-n может получить больший выигрыш от использования операций SSE или даже графического процессора (см., Например, gpu.js).
В любом случае, решение зависит от конкретной системы Forth.
Пример (концептуальная модель)
При использовании матриц и библиотек пула потоков умножение матриц может выглядеть следующим образом:
\ matrices vocabulary is in the context.
slot-enum{ m1 m2 m3 tp }slot-enum
: calc-item { r c -- }
0e m1 columns 0 do
r i m1 item
i c m2 item
F* F+
loop r c m3 item!
;
: mult-matrix ( a b c -- ) \ c = a * b
m3! m2! m1!
\ m3 dimenisions should be m1 rows x m2 columns
threadpool::new-group tp!
m1 rows 0 do m2 columns 0 do
i j 2 'calc-item tp threadpool::run
loop
tp threadpool::join
tp threadpool::free
;