Concurrency 同时应用谓词筛选列表(SWI Prolog) 我的问题是:应用谓词并行过滤列表

Concurrency 同时应用谓词筛选列表(SWI Prolog) 我的问题是:应用谓词并行过滤列表,concurrency,prolog,swi-prolog,Concurrency,Prolog,Swi Prolog,我有一个列表,还有一个谓词。实际上,这是一个很长的列表,谓词需要一段时间。我只想输出满足谓词的列表元素 我可以访问很多CPU内核,所以我认为尝试以块为单位并行测试列表中的元素是有意义的 我试过的东西: [concurrent\]maplist不起作用 看起来应该很容易。似乎是maplist的简单并发版本 根据我的建议,maplist/3应该完全按照我的要求来做。对于SWI的maplist/3建议,其行为可能与答案中所述不符,但在评论中,答案的作者建议这是文档中的一个问题,它确实应该按预期工作 这

我有一个列表,还有一个谓词。实际上,这是一个很长的列表,谓词需要一段时间。我只想输出满足谓词的列表元素

我可以访问很多CPU内核,所以我认为尝试以块为单位并行测试列表中的元素是有意义的

我试过的东西: [
concurrent\
]
maplist
不起作用 看起来应该很容易。似乎是
maplist
的简单并发版本

根据我的建议,
maplist/3
应该完全按照我的要求来做。对于SWI的
maplist/3
建议,其行为可能与答案中所述不符,但在评论中,答案的作者建议这是文档中的一个问题,它确实应该按预期工作

这似乎对我不起作用

我已经对其进行了如下测试:

:- use_module(library(apply)).

f(A):-
   (A*A < 10),
   writeln(A).

 set(0,[]).
 set(N,T):- N2 is N-1, set(N2,T1), append(T1,[N],T).
与普通地图列表相同的问题:

set(4,L), maplist(f, L, O).
ERROR: Undefined procedure: f/2
ERROR:   However, there are definitions for:
ERROR:         f/1
include
起作用,但不是并行的 我想要做的(不是并行的)是
包含

?- set(11,L), include(f, L, O).
1
2
3
L = [1, 2, 3, 4, 5, 6, 7, 8, 9|...],
O = [1, 2, 3] .
并发运行
[edit]运行!但这是平行的吗? 我一直在努力让它工作,部分遵循的例子

正在加载此文件:

set(0,[]):-!.
set(N,T):- N2 is N-1, set(N2,T1), append(T1,[N],T).
f(A, B):-
    (A*A < B),
    writeln(A).
par_test(A, B):-
    set(A, S),
    findall(f(Good, B), (member(Good, S)), Goals),
    concurrent(8, Goals, []).
但是看一下
htop
(用一个长得多的运行谓词代替这个
f
),它似乎只在一个核心上运行:-(

我如何并行地执行此操作?
有没有一种方法可以通过
并发映射列表
,或者类似简单的并行版本的
包含
,或者另一种方法来实现这一点呢?

映射列表
将第一个参数作为谓词,并将每个列表中的一个元素作为
ma的参数应用于该谓词plist
。这必然意味着
maplist
的所有列表参数都具有相同数量的元素。在这种情况下
f
接受一个参数,但
maplist(f,,)
期望
f
接受两个参数。因此,错误的未定义过程:f/2,这意味着Prolog无法找到具有两个参数的
f

因此,
maplist
并不能真正满足您的需要。您需要的是在某些其他语言中被称为
select
的东西,在这些语言中,您只在第二个列表中包含通过应用于第一个列表中的元素的过滤器的元素

下面是一个示例实现:

select(_, [], []).
select(Filter, [R|Rs], Fs) :-
    (   call(Filter, R)
    ->  Fs = [R|SF]
    ;   Fs = SF
    ),
    select(Filter, Rs, SF).
并调用,例如,
选择(f,L,O)

如您的示例所示,如果您有任何过滤器,其属性是它们将成功到达列表中的某一点,然后在此后继续失败,那么您可能希望优化过滤器本身,而不是让它在第一次失败后继续遍历列表

select_until_fail(_, [], []).
select_until_fail(Filter, [R|Rs], Fs) :-
    (   call(Filter, R)
    ->  Fs = [R|SF],
        select_until_fail(Filter, Rs, SF)
    ;   Fs = []
    ).
或者类似的(未经测试)


毕竟,我可能没有真正回答问题的“并发性”部分。

让我们测试并发映射列表:

test_concurrent_maplist(C) :-
    numlist(1,C,Ns),
    concurrent_maplist(prime,Ns,Ps),
    sumlist(Ps,N),
    format('we have ~d primes in first ~d natural numbers~n', [N,C]).
test_maplist(C) :-
    numlist(1,C,Ns),
    maplist(prime,Ns,Ps),
    sumlist(Ps,N),
    format('we have ~d primes in first ~d natural numbers~n', [N,C]).

prime(N,1) :-
    prime(N), !.
prime(_,0).

% from https://en.wikipedia.org/wiki/Primality_test
prime(N) :- N =< 1, !, fail.
prime(N) :- N =< 3, !.
prime(N) :- (0 is N mod 2; 0 is N mod 3), !, fail.
prime(N) :- prime_(N,5).

prime_(N,I) :-
    I * I =< N, !,
    ( ( 0 is N mod I; 0 is N mod (I + 2) ) -> fail
    ; J is I + 1, prime_(N,J)
    ).
prime_(_,_).
毫无疑问,这是一个进步:

?- F1 is (2.217/3.951)*100, F2 is (36.764/102.334)*100.
对于较长的列表,我们接近所用时间的1/3

代替并发映射列表/3,我们可以坚持使用并发映射列表/2,并将结果存储在数据库、全局变量等中。

谢谢,
include
(在SWI中)按照您的
select
所述完成工作。我的主要问题是并发部分-但是“选择直到失败”的想法很有帮助,谢谢!
test_concurrent_maplist(C) :-
    numlist(1,C,Ns),
    concurrent_maplist(prime,Ns,Ps),
    sumlist(Ps,N),
    format('we have ~d primes in first ~d natural numbers~n', [N,C]).
test_maplist(C) :-
    numlist(1,C,Ns),
    maplist(prime,Ns,Ps),
    sumlist(Ps,N),
    format('we have ~d primes in first ~d natural numbers~n', [N,C]).

prime(N,1) :-
    prime(N), !.
prime(_,0).

% from https://en.wikipedia.org/wiki/Primality_test
prime(N) :- N =< 1, !, fail.
prime(N) :- N =< 3, !.
prime(N) :- (0 is N mod 2; 0 is N mod 3), !, fail.
prime(N) :- prime_(N,5).

prime_(N,I) :-
    I * I =< N, !,
    ( ( 0 is N mod I; 0 is N mod (I + 2) ) -> fail
    ; J is I + 1, prime_(N,J)
    ).
prime_(_,_).
?- time(test_concurrent_maplist(100000)).
we have 9592 primes in first 100000 natural numbers
% 2,100,109 inferences, 1.799 CPU in 2.217 seconds (81% CPU, 1167205 Lips)
true.

?- time(test_concurrent_maplist(1000000)).
we have 78498 primes in first 1000000 natural numbers
% 21,000,109 inferences, 18.244 CPU in 36.764 seconds (50% CPU, 1151063 Lips)
true.

?- time(test_maplist(100000)).
we have 9592 primes in first 100000 natural numbers
% 16,151,437 inferences, 3.942 CPU in 3.951 seconds (100% CPU, 4096903 Lips)
true.

?- time(test_maplist(1000000)).
we have 78498 primes in first 1000000 natural numbers
% 402,953,287 inferences, 102.334 CPU in 102.302 seconds (100% CPU, 3937617 Lips)
true.
?- F1 is (2.217/3.951)*100, F2 is (36.764/102.334)*100.