-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathnd_threads.pro
163 lines (128 loc) · 3.9 KB
/
nd_threads.pro
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
% thread pool mechanism for execution of
% _nondeterministically_ generated nondeterministic goals
% a form of staged programming: a generator creates goals
% it is usable to run things in constant space, no recursion involved
test_nondet_first:-
Gen=(
between(1,100,I),
Gs=(between(1,100,K),I is 100-K,I mod 10=:=0)
),
Exec=Gs,
Sol=I,
%Gen,(Exec),
nondet_first(Sol,Exec,Gen),
ppp(sol=Sol),
fail
; ppp(done).
nondet_first(Sol,Exec,ExecGen):-
thread_count(ThreadCnt),
nondet_first_with(ThreadCnt,Sol,Exec,ExecGen).
nondet_first_with(ThreadCnt,Sol,Exec,ExecGen):-
%WorkSize is ThreadCnt*10,WorkOpt=[max_size(WorkSize)],
%SolsOpt=[max_size(1)],
WorkOpt=[],
SolsOpt=[],
message_queue_create(Master,WorkOpt),
message_queue_create(Sols,SolsOpt),
findall(Id,
(
between(1,ThreadCnt,_),
thread_create(nondet_worker_with(Sols,Master),Id,[])
),
Ids),
forall(
ExecGen, % send as much work as generated
thread_send_message(Master,Sol-Exec)
),
thread_get_message(Sols,Sol),
forall(
member(Id,Ids),
catch(thread_signal(Id, abort), _, true)
),
message_queue_destroy(Master),
message_queue_destroy(Sols).
nondet_worker_with(Sols,Master):-
thread_get_message(Master,Goal),
Goal=X-G,
G,
!,
thread_send_message(Sols,X).
nondet_worker_with(Sols,Master):-
nondet_worker_with(Sols,Master).
thread_stop:-abort.
send_or_switch_to_seq(ThreadCnt,Queue,Sols,Sol-Exec):-
message_queue_property(Queue,size(Size)),Size>ThreadCnt*ThreadCnt,
!,
once(Exec),thread_send_message(Sols,Sol).
send_or_switch_to_seq(_ThreadCnt,Queue,_Sols,Sol-Exec):-
thread_send_message(Queue,Sol-Exec).
%%%%%
nondet_run(Exec,ExecGen):-thread_count(ThreadCnt),nondet_run_with(ThreadCnt,Exec,ExecGen).
nondet_run_with(ThreadCnt,Exec,ExecGen):-
message_queue_create(Master,[]),
findall(Id,
(
between(1,ThreadCnt,_),
thread_create(nondet_worker(Master),Id,[])
),
Ids),
( ExecGen,
% send as much work as generated
thread_send_message(Master,Exec),%ppp(sent=Exec),
fail
; % send as many stops as threads, but AFTER the work is done
forall(member(_,Ids),thread_send_message(Master,'$stop'))
),
maplist(thread_join,Ids,_),
message_queue_destroy(Master).
thread_count(ThreadCnt):-
prolog_flag(cpu_count,MaxThreads),
ThreadCnt is max(2,ceiling((2/3)*MaxThreads)).
nondet_worker(Master):-
repeat,
thread_get_message(Master,Goal),
( Goal='$stop',!
; Goal,
fail
).
nondet_run(Exec,ExecGen,Action):-nondet_run((Exec,Action),ExecGen).
% example of use and tests
% runs in parallel counting solutions
% uses an ExecGenerator for which runs each
% generated Goal in thread pool
nondet_count(Exec,ExecGen,SolCount):-
thread_count(Threads),
nondet_count_with(Threads,Exec,ExecGen,SolCount).
nondet_count_with(Threads,Exec,ExecGen,SolCount):-
count_init,
nondet_run_with(Threads,exec_sol_count(Exec),ExecGen),
count_get(SolCount).
exec_sol_count(G):-sols(G,K),count_inc(K).
count_init:-flag(sol_count,_,0).
count_inc:-flag(sol_count,K,K+1).
count_inc(C):-flag(sol_count,K,K+C).
count_get(K):-flag(sol_count,K,K).
det_count(Exec,ExecGen,SolCount):-
count_init,
(ExecGen,exec_sol_count(Exec),fail;true),
count_get(SolCount).
nondet_run1(Exec,ExecGen):-
thread_count(ThreadCnt),Max is ThreadCnt*ThreadCnt,
findnsols(
Max,
Exec,
call(ExecGen),
Execs
),
nondet_run(Exec,member(Exec,Execs)),
fail
; true.
nondet_run1(Exec,ExecGen,Action):-nondet_run1((Exec,Action),ExecGen).
nondet_count1(Exec,ExecGen,SolCount):-
count_init,
nondet_run1(Exec,ExecGen,count_inc),
count_get(SolCount).
nondet_test:-time(nondet_test(1000)).
nondet_test(N):-nondet_count(between(1,J,_),between(1,N,J),Res),writeln(Res).
det_test:-time(det_test(1000)).
det_test(N):-det_count(between(1,N,J),between(1,N,J),Res),writeln(Res).