在 Lparallel 库中使用队列 (Common Lisp)

2024-02-19

lparallel 库中队列的基本讨论位于https://z0ltan.wordpress.com/2016/09/09/basic-concurrency-and-parallelism-in-common-lisp-part-4a-parallelism-using-lparallel-fundamentals/#channels https://z0ltan.wordpress.com/2016/09/09/basic-concurrency-and-parallelism-in-common-lisp-part-4a-parallelism-using-lparallel-fundamentals/#channels说队列“启用工作线程之间的消息传递”。下面的测试使用共享队列来协调主线程和从属线程,其中主线程在退出之前只是等待从属线程完成:

(defun foo (q)
  (sleep 1)
  (lparallel.queue:pop-queue q))  ;q is now empty

(defun test ()
  (setf lparallel:*kernel* (lparallel:make-kernel 1))
  (let ((c (lparallel:make-channel))
        (q (lparallel.queue:make-queue)))
    (lparallel.queue:push-queue 0 q)
    (lparallel:submit-task c #'foo q)
    (loop do (sleep .2)
             (print (lparallel.queue:peek-queue q))
          when (lparallel.queue:queue-empty-p q)
            do (return)))
  (lparallel:end-kernel :wait t))

这按预期产生输出:

* (test)

0
0
0
0
NIL
(#<SB-THREAD:THREAD "lparallel" FINISHED values: NIL {10068F2B03}>)

我的问题是我是否正确或完全使用了 lparallel 的队列功能。队列似乎只是使用全局变量来保存线程共享对象的替代品。使用队列的设计优势是什么?为每个提交的任务分配一个队列(假设任务需要通信)通常是一种好的做法吗?感谢您提供更深入的见解。


多线程工作是通过管理对可变对象的并发访问来完成的 共享状态,即你有一个公共数据结构的锁, 每个线程都对其进行读取或写入。

然而,建议尽量减少数据的数量 同时访问。队列是一种将工作人员与每个工作人员解耦的方法 其他,通过让每个线程管理其本地状态并交换数据 只能通过消息;这是线程安全的,因为访问 队列由以下控制锁和状况 变量 https://en.wikipedia.org/wiki/Monitor_(synchronization).

你在主线程中正在做的是polling当队列 是空的;这可能有效,但这会适得其反,因为队列 用作同步机制,但在这里你正在做 自己同步。

(ql:quickload :lparallel)
(defpackage :so (:use :cl
                      :lparallel
                      :lparallel.queue
                      :lparallel.kernel-util))
(in-package :so)

让我们改变foo这样它就有两个队列,一个用于传入 一个用于请求,一个用于回复。在这里,我们进行一个简单的变换 正在发送的数据,对于每条输入消息,只有一个 输出消息,但情况并不总是如此。

(defun foo (in out)
  (push-queue (1+ (pop-queue in)) out))

Change test这样控制流仅基于对队列的读/写:

(defun test ()
  (with-temp-kernel (1)
    (let ((c (make-channel))
          (foo-in (make-queue))
          (foo-out (make-queue)))
      (submit-task c #'foo foo-in foo-out)
      ;; submit data to task (could be blocking)
      (push-queue 0 foo-in)
      ;; wait for message from task (could be blocking too)
      (pop-queue foo-out))))

但是,如果有多个任务正在运行,如何避免测试中的轮询呢?您是否不需要不断检查其中任何一项何时完成,以便可以将更多工作推送到队列中?

您可以使用不同的并发机制,类似于listen http://man7.org/linux/man-pages/man2/listen.2.html and 轮询/epoll http://man7.org/linux/man-pages/man7/epoll.7.html,您可以在其中观看多个 事件源并在其中之一准备好时做出反应。有类似的语言Go (select https://tour.golang.org/concurrency/5) and Erlang (receive http://erlangbyexample.org/send-receive) 在哪里 这是很自然的表达。在 Lisp 方面,Calispel https://www.cliki.net/Calispel库提供了类似的交替机制(pri-alt and fair-alt)。例如,以下内容取自 Calispel 的测试代码:

(pri-alt ((? control msg)
          (ecase msg
            (:clean-up (setf cleanup? t))
            (:high-speed (setf slow? nil))
            (:low-speed (setf slow? t))))
         ((? channel msg)
          (declare (type fixnum msg))
          (vector-push-extend msg out))
         ((otherwise :timeout (if cleanup? 0 nil))
          (! reader-results out)
          (! thread-expiration (bt:current-thread))
          (return)))

如果是并行,没有这样的机制,但是只要您使用标识符标记消息,您就可以仅使用队列走得很远。

如果您需要尽快做出反应either a task t1 or t2给出结果,然后使这两个任务写入同一结果通道:

(let ((t1 (foo :id 1 :in i1 :out res))
      (t2 (bar :id 2 :in i2 :out res)))
   (destructuring-bind (id message) (pop-queue res)
     (case id
       (1 ...)
       (2 ...))))

如果您需要同步代码t1 and t2发出结果,让他们写入不同的通道:

(let ((t1 (foo :id 1 :in i1 :out o1))
      (t2 (bar :id 2 :in i2 :out o2)))
   (list (pop-queue o1)
         (pop-queue o2)))
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Lparallel 库中使用队列 (Common Lisp) 的相关文章

  • ConcurrentHashMap.computeIfAbsent 和 ConcurrentHashMap.computeIfPresent 中 `mappingFunction` 的执行

    我正在尝试查看实际的 Java 文档 描述了多少次的行为mappingFunction可以在传递给时调用ConcurrentHashMap computeIfAbsent and ConcurrentHashMap computeIfPre
  • 何时在多线程中使用 易失性?

    如果有两个线程访问全局变量 那么许多教程都说使该变量成为易失性的 以防止编译器将变量缓存在寄存器中 从而无法正确更新 然而 两个线程都访问共享变量需要通过互斥体进行保护 不是吗 但在这种情况下 在线程锁定和释放互斥体之间 代码位于关键部分
  • 使用 .Net HttpListener 进行多线程

    我有一个听众 listener new HttpListener listener Prefixes Add http 8077 listener Start listenerThread new Thread HandleRequests
  • 为什么单线程异常会导致整个程序崩溃(如何防止这种情况?)

    例如 如果我跑步 int x 0x00000 程序崩溃了 但为什么整个程序崩溃而不是单个线程崩溃呢 我创建了多个连续睡眠的线程来测试这一点 有什么方法可以让当前线程退出 而不是整个程序 在Windows上使用winapi Thanks 但为
  • 唤醒单个线程而不是 pthread 中的忙等待

    我不确定标题是否反映了我在这里提出的问题 但这是我在没有很长的标题的情况下能做的最好的事情 我正在尝试实施一个worker thread模型中pthreads 我想从中产生一组线程main函数以及此后的main线程将工作委托给工作人员 并等
  • 通过不同的线程使用多个 ORB(多线程多 Orb 客户端应用程序) - 如何?

    This question is related to Is it possible to have several ORB objects in the same process https stackoverflow com quest
  • Python:threading.timer不尊重间隔

    这是后续另一个问题 https stackoverflow com questions 32286049 python accept input while waiting 我现在有了一个解决方案 但由于不相关的原因 实现似乎没有正常运行
  • C++并行std::sort用于浮点值

    我有一个包含数百万个浮点值的大文件 我可以使用轻松对它们进行排序std sort通过将文件读入vector现在 例如 std vector
  • 一次性的 lisp 宏,我的实现正确吗?

    我正在尝试从 Peter Seibel 的书 Practical Common Lisp 中学习 Lisp 在第 8 章 宏 定义你自己的 http www gigamonkeys com book macros defining your
  • 无法从 run 方法中访问对象的属性(方法)! Java多线程

    我在 ServerConnectionManager 中有以下代码 public class ServerConnectionManager implements Runnable private DatagramPacket receiv
  • 尝试删除文件时如何调试“共享冲突”

    我有一个多线程 C 应用程序 它创建文件 打开文件进行处理 然后在完成后删除它们 此应用程序预计会处理 1 100 个文件 当我尝试在处理后删除文件时 有点随机 很可能归因于应用程序的多线程性质 我遇到共享冲突 我的直觉告诉我 维克 你在尝
  • Android SurfaceView 使用线程绘制画布

    我正在尝试使用线程在画布上绘图来创建一个简单的游戏引擎 但我遇到了一些无法解释的奇怪问题 这个 游戏 的目的是每秒在画布上画一个圆圈 这是可行的 但不是我想要的工作方式 似乎应用程序正在两个画布之间切换 并向每个画布添加一个圆圈 这样您就可
  • 如何在 C++ 中急于提交分配的内存?

    总体情况 带宽 CPU 使用率和 GPU 使用率都极其密集的应用程序需要每秒从一个 GPU 向另一个 GPU 传输约 10 15GB 的数据 它使用 DX11 API 来访问 GPU 因此上传到 GPU 只能在每次上传都需要映射的缓冲区中进
  • 为什么绿色线程不能在多核上工作

    在维基百科上 绿色线程 http en wikipedia org wiki Green threads被描述为通常无法在多核上运行 而没有解释原因 在多核处理器上 本机线程实现可以 自动将工作分配给多个处理器 而绿色线程 实现通常不能 我
  • 防止重入并确保某些操作获取锁的正确方法是什么?

    我正在设计一个基类 当继承该基类时 它将针对多线程环境中的上下文提供业务功能 每个实例可能都有长时间运行的初始化操作 所以我想让这些对象可重用 为此 我需要能够 为这些对象之一分配上下文以允许其完成工作 防止对象在已有上下文的情况下被分配新
  • 如何唤醒正在休眠的线程?

    我在加载事件中创建了一个线程 如下所示 Thread checkAlert null bool isStop false private void frmMain Load object sender EventArgs e checkAl
  • 优化计算中使用的 # 个线程的算法

    我正在执行一个操作 我们将其称为CalculateSomeData CalculateSomeData 在连续的 代 中运行 编号为 1 x 整个运行中的代数由CalculateSomeData 的输入参数固定 并且是先验已知的 完成一次生
  • 临时表是线程安全的吗?

    我正在使用 SQL Server 2000 它的许多存储过程广泛使用临时表 数据库的流量很大 我担心创建和删除临时表的线程安全性 假设我有一个存储过程 它创建了一些临时表 它甚至可以将临时表连接到其他临时表等 并且还可以说两个用户同时执行存
  • asp.net core / kestrel中的线程管理

    我正在解决我们已迁移到 asp net core 2 0 的 asp net 应用程序的性能 可扩展性问题 我们的应用程序作为应用程序服务托管在 azure 上 并且在任何中等流量的情况下都很容易崩溃 让我困惑的一件事是如何处理多个并发请求
  • 无锁算法真的比全锁算法性能更好吗?

    陈雷蒙德 http blogs msdn com b oldnewthing 一直在做一个huge http blogs msdn com b oldnewthing archive 2011 04 15 10154245 aspx ser

随机推荐