我对 Forth 编程语言有一段时间的简短了解。是否可以在 Forth 中使用同步原语进行多线程处理?
例如,是否可以在 Forth 中使用多个线程进行 n×n 矩阵乘法?如果是这样,基本机制或编程模式是什么?
我对 Forth 编程语言有一段时间的简短了解。是否可以在 Forth 中使用同步原语进行多线程处理?
例如,是否可以在 Forth 中使用多个线程进行 n×n 矩阵乘法?如果是这样,基本机制或编程模式是什么?
对于既定目标,多线程必须是先发制人的。Simple Forths 有一个暂停任务循环,一个接一个地运行任务,从不重叠。出人意料地有用,但在这种情况下不是。
现代、专业的 Forth 可以进行多线程处理,但我知道只有一种具有特殊原语以使其更容易。
前面给出的示例矩阵乘法不是多线程的演示。
据我所知 (*),只有 iForth 编译器具有特殊的多线程原语(基于 OCCAM),并附带了在 n 核处理器(其中 x < n)上运行速度真正快 x 倍的示例。对于矩阵代码,我将使用它的 PAR .. ENDPAR 线程访问在内存中相距很远的行和列,以防止缓存污染。还有另一个原语可以自动为您拆分 DO-LOOP,按照此任务所需的方式。8 个线程的此语法示例如下:
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 也可以进行多线程处理。(它们在应用程序中是一样的。)现在几乎所有的 Forths 都可以做到。
您可以执行以下操作:
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中的同步原语和多线程大多只是 Windows 和 Linux (pthreads) API 上的通用包装器。
请注意,应该使用线程池来为小型操作提供更好的性能——因为创建/销毁线程可能是耗时的操作。
此外,n×n 矩阵乘法的实现也有可能通过使用SSE 操作甚至 GPU 获得更好的收益(例如参见 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
;