Поддерживает ли Forth многопоточность?

Некоторое время я немного взглянул на язык программирования Forth. Можно ли сделать многопоточность с примитивами синхронизации в Forth?

Например, возможно ли сделать матричное умножение n на n с несколькими потоками в Forth? Если да, то каков основной механизм или шаблоны программирования?

3 ответа

Для заявленной цели многопоточность должна быть преимущественной. В Simple Forths есть цикл задач PAUSE, который запускает задачи одну за другой, не перекрывая друг друга. Удивительно полезно, но не в этом случае.

Современный, профессиональный, Forth может выполнять многопоточность, но я знаю только один со специальными примитивами, чтобы сделать его проще.

Приведенный выше пример умножения матриц не является демонстрацией многопоточности.

Насколько мне известно (*), только компилятор iForth имеет специальные многопоточные примитивы (на основе OCCAM) и поставляется с примерами, которые действительно работают в x раз быстрее на n-ядерных процессорах (где x

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 ;

Для матриц 1024 x 1024 это (mmul2) примерно в два раза быстрее, чем однопоточная версия (mmul1).

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

(*) Ходят слухи, что MPE и Forth Inc недавно добавили похожую функциональность.

Любой 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
;
Другие вопросы по тегам