- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
SWI-Prolog advertises itself as a single-language replacement for the LAMP stack .说到更换 男 (ySQL),文档列举了几种方法,其中 library(persistency)
似乎是能够提供持久的、可更新的数据库的最简单的方法。
library(persistency)
的文档提供了以下示例,该示例展示了如何在读取和更新数据库时使用互斥体来避免无效状态:
:- module(user_db,
[ attach_user_db/1, % +File
current_user_role/2, % ?User, ?Role
add_user/2, % +User, +Role
set_user_role/2 % +User, +Role
]).
:- use_module(library(persistency)).
:- persistent
user_role(name:atom, role:oneof([user,administrator])).
attach_user_db(File) :-
db_attach(File, []).
%% current_user_role(+Name, -Role) is semidet.
current_user_role(Name, Role) :-
with_mutex(user_db, user_role(Name, Role)).
add_user(Name, Role) :-
assert_user_role(Name, Role).
set_user_role(Name, Role) :-
user_role(Name, Role), !.
set_user_role(Name, Role) :-
with_mutex(user_db,
( retractall_user_role(Name, _),
assert_user_role(Name, Role))).
mutex
,它指出
The predicate
with_mutex/2
behaves asonce/1
with respect to the guarded goal. This means that our predicateaddress/2
is no longer a nice logical non-deterministic relation.
Message queues (see
message_queue_create/3
) often provide simpler and more robust ways for threads to communicate.
library(persistency)
例如,将互斥锁的使用替换为更合适的消息队列使用,确保数据库状态的持续有效性而不牺牲非确定性关系。
最佳答案
在 SWI Prolog 中,每个线程都有自己的消息队列。因此,您可以在线程上运行数据库服务器,并让客户端将查询发布到数据库的消息队列。数据库将一次处理一个请求,以便数据库始终有效。查询仍然是确定性的(如 once/1),但正如您所指出的,与 with_mutex/2
的情况不同,可以通过关系指定数据库关系本身。
[注意,我正在展示如何使用内置的 SWI Prolog 消息队列来执行此操作,但您也可以使用 Pengines为此,这可能对用户更友好,并且内置了对远程执行的支持。]
首先,我将删除 with_mutex
调用:
:- module(user_db,
[ attach_user_db/1, % +File
current_user_role/2, % ?User, ?Role
add_user/2, % +User, +Role
set_user_role/2 % +User, +Role
]).
:- use_module(library(persistency)).
:- persistent
user_role(name:atom, role:oneof([user,administrator])).
attach_user_db(File) :-
db_attach(File, []).
%% current_user_role(+Name, -Role) is semidet.
current_user_role(Name, Role) :-
user_role(Name, Role).
add_user(Name, Role) :-
assert_user_role(Name, Role).
set_user_role(Name, Role) :-
user_role(Name, Role), !.
set_user_role(Name, Role) :-
retractall_user_role(Name, _),
assert_user_role(Name, Role).
:- debug(db),
打开调试消息我发现它在多线程代码中是必不可少的。
db
并且它是“分离的”,所以它会在系统退出时被清理。该线程通过调用
db_run/0.
启动
db_up(File, DbThreadId) :-
db_attach(File, []),
thread_create(db_run, DbThreadId, [detached(true), alias(db)]),
debug(db, 'db thread created~n').
db_run :-
debug(db, 'db_run:...', []),
repeat,
thread_get_message(db, Msg, []),
debug(db, 'Received: ~p', [Msg]),
Msg,
debug(db, 'db_query succeeded', []),
fail.
db_query(<Query>, <ClientThreadId>)
的消息,所以我们需要一个谓词
db_query/2
实际运行计算。它向客户端线程发送成功、失败或异常消息。
:- meta_predicate user_db:db_query(0,*).
db_query(Goal, ClientId) :-
catch((Goal -> Status = true; Status = false),
Err,
Status = err(Err)),
( Status = true ->
Response = db_response(succ(Goal))
;
Status = false ->
Response = db_response(fail)
;
Status = err(Err) ->
Response = db_response(err(Err))
),
debug(db, 'db_query/2: sending message ~w to ~p', [Response, ClientId]),
thread_send_message(ClientId, Response).
client_wait/1
等待响应。 .
:- meta_predicate client_post(0).
client_post(Goal) :-
thread_self(Me),
Msg = db_query(Goal, Me),
debug(db, 'client_post/1: sending message ~p...', [Msg]),
thread_send_message(db, Msg),
debug(db, 'client_post/1: waiting...', []),
client_wait(Goal).
client_wait/1
等待 db_response() 形式的消息(在失败前最多等待 1 秒,但您可能想要做一些更聪明的事情)。它
:- meta_predicate client_wait(0).
client_wait(Goal) :-
thread_self(Me),
thread_get_message(Me, db_response(Term), [timeout(1)]), % blocks until db_response(_) arrives
Msg = db_response(Term),
debug(db, 'Client received ~p', [Msg]),
( Term = succ(Goal) ->
debug(db, 'client_wait/1: exit with true', []),
true
;
Term = fail ->
fail
;
Term = err(Err) ->
throw(Err)
;
domain_error(db_response_message, Msg)
).
$ swipl -l db_thread.pl
Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 7.3.24-127-g9b94a9f-DIRTY)
Copyright (c) 1990-2016 University of Amsterdam, VU Amsterdam
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.
Please visit http://www.swi-prolog.org for details.
For help, use ?- help(Topic). or ?- apropos(Word).
?- user_db:db_up('db.pl', DB).
db thread created
DB = db.
?- Xs = [bob-administrator, john-user, bill-user], user_db:client_post(forall(member(U-R, Xs), add_user(U, R))).
Xs = [bob-administrator, john-user, bill-user].
?- findall(U, user_db:client_post(current_user_role(U, user)), Users). %% queries are posted as in once/1
Users = [john].
?- user_db:client_post(findall(U, current_user_role(U, user), Users)). %% but db predicates are themselves relational
Users = [john, bill].
test_db.pl
,我创建数据库,并运行两个线程。正在运行的一个
toggle/0
在两个用户角色数据库和另一个之间切换,运行
print/0
只是打印出用户和他们的角色。我们在时间上随机地切换世界 200 次。同时,另一个线程以随机间隔的 200 次打印出 db。
test_db.pl
:
:- use_module(user_db).
:- initialization user_db:db_up('db.pl', _), test.
world(1, [bob-administrator,
john-user]).
world(2, [bob-user,
john-administrator]).
set_world(I) :-
world(I, Xs),
forall(member(U-R, Xs),
set_user_role(U, R)).
print_world :-
findall(U-R,
current_user_role(U, R),
URs),
sort(URs, URs1),
format('~p~n', [URs1]).
random_sleep :-
random(R),
X is R * 0.05,
sleep(X).
toggle(0) :- !.
toggle(N) :-
forall(world(I, _),
(user_db:client_post(set_world(I)),
random_sleep)),
succ(N0, N),
toggle(N0).
print(0) :- !.
print(N) :-
user_db:client_post(print_world),
succ(N0, N),
random_sleep,
print(N0).
test :-
thread_create(toggle(100), Id1, []),
thread_create(print(200), Id2, []),
thread_join(Id1, _),
thread_join(Id2, _).
$ swipl -l test_db.pl
运行它:
[bob-administrator,john-user]
[bob-administrator,john-user]
[bob-user,john-administrator]
[bob-administrator,john-user]
[bob-user,john-administrator]
[bob-administrator,john-user]
[bob-user,john-administrator]
[bob-administrator,john-user]
[bob-administrator,john-user]
[bob-user,john-administrator]
[bob-administrator,john-user]
[bob-user,john-administrator]
[bob-administrator,john-user]
...
关于multithreading - SWI-Prolog:使用消息队列进行线程安全的数据库读/写, `library(persistency)`,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40088552/
我正在学习序言。 在我看来,prolog 的规则(关系和简单的事实)是“肯定的”——他们说的是或可能是真的。 向 prolog 程序添加新的此类规则只会增加“正面”知识。它不能添加“负面”事实来说明某
希望你一切都好。我是 prolog 的新手,我在编写代码时遇到问题。这段代码的目的很简单。它将列表中的每个元素添加到最后一个。我可以用 Java 做的事情是: static void add(
在closed-world assumption下, what is not currently known to be true, is false Prolog 的语义通常被称为遵循封闭世界假设,
我正在 Prolog (swi-prolog) 中做我的第一步,但无法解决以下问题:如何将存在量化的规则包含在我的事实中;具体来说,我如何包含句子“每个人都是某人的 friend ”\forall x
我知道如何以过程方式(即,在 C++、Java 等中)对 BST 执行范围查询,但我发现很难转换为 Prolog 语言。 程序的方式应该是这样的: http://www.geeksforgeeks.o
Prolog 中是否有(相对)当前最佳实践的引用资料?一本适合没有学习过逻辑编程或“Prolog 的工艺”等高级文本的商业 Prolog 开发人员? 有很多通用教程,但我能找到的关于最佳实践的唯一一个
这是CFG: S -> T | V T -> UU U -> aUb | ab V -> aVb | aWb W -> bWa | ba 所以这将接受某种形式的: {a^n b^n a^m b^m |
我目前有以下问题,我想用 Prolog 解决。这是一个简单的例子,很容易在 Java/C/whatever 中解决。我的问题是,我认为与 Java 的思想联系太紧密,无法以利用 Prolog 逻辑能力
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我无法理解差异列表,尤其是在这个谓词中: palindrome(A, A). palindrome([_|A], A). palindrome([C|A], D) :- palindrome(A
(这不是一个类(class)作业问题。只是我自己的个人学习。) 我正在尝试在 Prolog 中进行练习以从列表中删除元素。这是我的代码: deleteall([],X,[]). deleteall([
我最近试图了解 Prolog,它似乎可以很好地映射到很多领域,但我无法弄清楚它可能不擅长什么。 那么它有什么不好的(除了需要实时/无 gc 性能的东西)? 最佳答案 我同意你的一般评估,即 Prolo
我正在组装一个简单的元解释器,它输出证明的步骤。我无法将证明步骤作为输出参数。我的谓词 explain1 以我想要的详细形式返回证明,但不是作为输出参数。我的谓词 explain2 将证明作为输出参数
hi(g,plus(A,B),int) :- hi(g,A,int),hi(g,B,int),!. 在上面的语句中 '!' 是什么意思?在声明的末尾签名吗? 最佳答案 那是 cut operator
有没有一种简单的方法可以让 prolog 中的查询只返回每个结果一次? 例如我正在尝试类似的东西: deadly(Xn) :- scary(X), Xn is X - 1, Xp is X + 1,
我正在尝试学习 Prolog。这是我使用这种语言的第一步。作为练习,我想编写可以识别一些扑克手牌的程序(同花顺、同花顺、满屋等)。 我正在 Prolog 中寻找良好的卡片表示。我需要有可能检查一张卡片
我刚刚被介绍到 Prolog 并且正在尝试编写一个谓词来查找整数列表的最大值。我需要写一个从头开始比较,另一个从结尾比较。到目前为止,我有: max2([],R). max2([X|Xs], R):-
我试图在Prolog中编写谓词palindrome/1,当且仅当其列表输入包含回文列表时才为true。 例如: ?- palindrome([1,2,3,4,5,4,3,2,1]). 是真的。 有什么
我正在尝试编写一个程序,该程序将两个列表作为输入并检查适当的子集。我开始于: proper([A],[]). proper([],[A]). proper([A|T1],[A|T2]) :- prop
我是 Prolog 的新手,我正在使用 SWI-Prolog v6.6 在 *.pl 中存储断言文件。 :- dynamic fact/2. assert(fact(fact1,fact2)). 使用
我是一名优秀的程序员,十分优秀!