swi-polog中的多线程提供了一些改进

时间:2016-09-10 00:01:18

标签: multithreading prolog swi-prolog

我有一个带有繁重计算的代码:执行pred(In, Out)让我们说64K次,每次执行需要1-10秒。

我想使用多线程(64)机器来加速这个过程。 我使用concurrent_maplist

concurrent_maplist(pred, List_of_64K_In, List_of_64K_Out).

我的速度增加了大约8倍但不超过这个速度。 我认为原因是concurrent_maplist上的以下通知:

  

请注意,此谓词的开销很大   因此,在达到加速之前,目标必须相当昂贵。

为了使目标相当昂贵,我将代码修改为:

% putting 1K pred/2 in heavy_pred/2 
concurrent_maplist(heavy_pred, List_of_64_List_of_1k_In, List_of_64_List_of_1k_Out).

heavy_pred(List_of_In, List_of_Out) :-
  maplist(pred, List_of_In, List_of_Out).

令人惊讶的是(对我而言),我没有进一步加快这一变化。

我想知道如何通过多线程进一步加快速度?

其他一些细节

架构:x86_64, AMD, 14.04.1-Ubuntu

swipl -v:SWI-Prolog version 6.6.4 for amd64

pred / 2是一个定理证明器,它采用公式并试图证明它们。 它使用的标准谓词几乎没有非标准谓词:cyclic_term/1write/1copy_term/2等。

2 个答案:

答案 0 :(得分:0)

要使内核正常工作,可以使用可由应用程序启动的线程。使用最新的swipl版本可以帮助您获得其提供的最新改进。

您还可以启动多个应用程序,每个应用程序例如8个线程。结果:更多的内核可以工作,尽管与运行具有更多线程的单个应用程序相比,总内核占用的内存更多。现在,您将需要管理不同的应用程序实例,以便整体工作进行(并且不会重复在其他应用程序上完成的工作)。我想即使在具有多个线程的单个应用程序的情况下也需要这样做。我的答案在技术上不是很严格,但是可以让您为CPU密集型工作使用更多的内核。

答案 1 :(得分:0)

当结果合并时,多核 CPU 不会线性扩展。我检查了 concurrent_maplist/2 和新的 concurrent_and/2 之间是否存在差异。我使用的示例包含来自 here 的相当大的工作项。

我添加了对 concurrent_maplist/2 的测试:

/* parallel, concurrent_maplist */
count3(N) :-
   findall(Y, between(1, 1000, Y), L),
   concurrent_maplist(slice, L, R),
   aggregate_all(sum(M), member(M, R), N).

有趣的是 concurrent_and/2 和 concurrent_maplist/2 之间没有太大区别。可能是因为工作项的数量只有 1000,因为工作项本身相当大。尽管如此,还是检查了 1'000'000 个数字的素性:

?- current_prolog_flag(cpu_count, X).
X = 8.

/* sequential */
?- time(count(N)).
% 138,647,812 inferences, 9.781 CPU in 9.792 seconds (100% CPU, 14174856 Lips)
N = 78499.

/* parallel, concurrent_and */
?- time(count2(N)).
% 4,450 inferences, 0.000 CPU in 2.458 seconds (0% CPU, Infinite Lips)
N = 78499.

/* parallel, concurrent_maplist */
?- time(count3(N)).
% 23,183 inferences, 0.000 CPU in 2.423 seconds (0% CPU, Infinite Lips)
N = 78499.

虽然机器有 8 个逻辑核心,但多亏了超线程。加速接近物理核心的数量,只有 4 个。所以如果你的机器有 64 个逻辑核心,这就是 cpu_count Prolog 标志返回的,你应该检查有多少物理核心。