Prolog中的并发抽象

问题描述 投票:2回答:3

我们正在构建Erlog​​ 1.0版本,该版本可以在Erlang进程中运行。目前,我已经实现了通过普通的erlang机制发送和接收消息的功能。但是,我希望能够将其他并发抽象添加到基于erlang消息传递的Erlog​​上。

那么,人们发现在Prolog或LP编程环境中还有哪些其他并发抽象有用?

concurrency erlang prolog actor erlog
3个回答
2
投票

tl; dr

记下OTP提供的主要抽象,故意记下您认为经常重复的情况,并在代码中开发出标准答案,以抽象出以前存在的任何临时方法。 (我想听起来很像重构。)

更长的答案

只要进程便宜到足以产生代码,程序员就永远不会考虑它们的成本,并且消息传递是共享数据的唯一方法,那么您就可以覆盖到要点。不过,基于这些不起眼的开始,通常会出现一些其他的模式,显然对抽象有帮助。

您可能会注意到的第一件事是您编写临时方法使同步呼叫变得安全的频率。作为very浅层示例,您将做类似(Erlang):

的操作
ask(Proc, Request, Data, Timeout) ->
    Ref = make_ref(),
    Proc ! {self(), Ref, {ask, Request, Data}},
    receive {Ref, Res} -> Res
    after Timeout -> {fail, timeout}
    end.

ask(Proc, Request, Data, Timeout) ->
    Ref = monitor(process, Proc),
    Proc ! {self(), Ref, {ask, Request, Data}},
    receive
        {Ref, Res} ->
            demonitor(Ref, [flush]),
            Res;
        {'DOWN', Ref, process, Proc, Reason} -> {fail, Reason}
    after Timeout -> {fail, timeout}
    end.

或其他。哪种方式开始进行同步调用并不重要(非监视方式或Monitor-Demonitor-Respond方式),关键是您应该将该模式包装到[[least类似于ask/4的单个函数中。 ],而不是在各处创建临时的同步调用例程。 (我对原始的Erlang项目的主要抱怨之一是,他们经常发现同步调用抽象方式的需求为时已晚。)

此特定问题是gen_server的全部内容的核心-处理内联过程“随即看起来像个好主意”的原始Erlang代码乱码,并将它们抽象为一个单一的概念以说明哪些服务流程通常做。

几乎不可避免的是,当您具有两个彼此同步发出信号的相同进程时,最终会开发出一种避免死锁的通用模式。我执行此操作的典型方法是生成一个中介程序来处理它,某些系统从不让两个完全相同定义的进程直接进行对话(一种通用仲裁),有时您只会看到“超时并返回到状态X”或其他内容。并非所有解决潜在死锁的方法都适用于每个系统,但这是在设计并发系统时会反复处理的问题。开始对发现死锁的情况进行分类并抽象化用于避免死锁的方法,这不是一个坏主意。

除了实现类似gen_server的东西外,我建议至少实现类似于OTP的gen_fsm的有限状态机抽象。在许多情况下,我发现OTP的这一部分甚至比gen_server更为有用,并且在手工编写了一百个fsm之后,我真的很感激gen_fsm处理其中大部分功能的效用(并且仍然保留handle_info,这是非常有用,因为无论如何,您必须以某种方式对其进行骇客地实现)。

OTP的抽象通常在过程级别上起作用。考虑可能要实例化的不是单个进程的哪种系统也可能会有帮助。例如,我一直在玩同级监督系统,并且显然那里出现了一些模式。如果我进一步进行研究,我将把我正在学习的有关这些系统如何工作的经验(例如,需要对癌症过程进行分类的方法等)分离为描述这种系统的Erlang行为和形式语法的组合,因此这样我就可以停止编写流程代码,而专注于我感兴趣的问题的级别。


2
投票
某些Prolog系统(例如Ciao,Qu-Prolog,SWI-Prolog,XSB和YAP)实现了多线程编程。这些实现通常会提升低级pthreads库(至少在POSIX操作系统中)。除了线程之外,其中一些系统还提供互斥和消息队列。使用这些基本模块,可以轻松实现的两个有用的抽象是

竞争或并行性和独立和并行性。在竞争性或并行性中,一组目标并发运行,直到其中一个成功(杀死其他目标)。一个使用示例将尝试使用一组试探法解决问题,而无需知道每种试探法都能更快地提供可接受的答案。在独立且并行的情况下,一组目标同时运行,并解释为合取。目标不共享变量(众所周知,共享对于并发是安全的,但有例外),所有目标都必须成功。一个使用示例通过将问题分解为必须成功解决每个子问题的子问题集来解决问题。您可以在例如上找到这些抽象的实现。 Logtalk(使用SWI-Prolog,XSB或YAP作为后端编译器运行时)和SWI-Prolog库上。 Logtalk发行版提供了使用这些抽象的几个示例。


0
投票
演员接收到的东西有点原始,因为它总是消耗匹配的消息队列条目。因此,例如,如果您想调用Future.isDone(),则可能需要向Erlang添加一个窥视器,该窥视器确实返回消息队列条目的副本,但仍然使消息队列保持原样。

否则,必须按以下方法解决,将未来推回队列:

isDone(Future) :- receive Future -> self(Pid), Pid ! Future; after 0 -> fail.

P.S .:您现在可以在Jekejeke Prolog中使用基于UDP的消息代理:https://gist.github.com/jburse/253739554305af625e746366cff9b66b#gistcomment-3089863
© www.soinside.com 2019 - 2024. All rights reserved.