【问题标题】:OCaml event/channel tutorial?OCaml 事件/频道教程?
【发布时间】:2012-03-03 23:10:33
【问题描述】:

我在 OCaml 中。

我正在寻找模拟通信节点,以查看消息在不同通信方案等下的传播速度。

节点可以 1. 发送和 2. 接收固定消息。我想显而易见的事情是将每个节点作为一个单独的线程。

显然,您可以使用 Event 模块和通道让线程相互传递消息,但我找不到任何示例。有人可以指出我正确的方向或只是给我一个简单的相关示例吗?

非常感谢。

【问题讨论】:

    标签: events ocaml channel message-passing


    【解决方案1】:

    听起来您正在考虑 John Reppy 的 Concurrent ML。 OCaml here 似乎有类似的东西。

    @Thomas 给出的答案也很有价值,但是如果您想使用这种并发编程风格,我建议您阅读 John Reppy 的 PhD thesis,它非常易读,并且非常清楚地处理了 CML 背后的动机和一些其使用的实质性例子。如果您对语义不感兴趣,则跳过该部分仍然可以阅读文档。

    【讨论】:

      【解决方案2】:

      是的,您可以使用 OCaml 的 Event 模块。您可以在在线O'Reilly book 中找到其使用示例。

      【讨论】:

        【解决方案3】:

        如果您要尝试模拟,那么您需要对节点进行更多的控制,而不是仅仅使用线程所允许的——或者至少,没有大的痛苦。

        我对此主题的主观方法是创建一个简单的单线程虚拟机,以保持对模拟的完全控制。在 OCaml 中这样做最简单的方法是使用类似 monad 的结构(例如在 Lwt 中所做的):

        (* A thread is a piece of code that can be executed to perform some
           side-effects and fork zero, one or more threads before returning. 
           Some threads may block when waiting for an event to happen. *)
        type thread = < run : thread list ; block : bool >
        
        (* References can be used as communication channels out-of-the box (simply 
           read and write values ot them). To implement a blocking communication 
           pattern, use these two primitives: *)
        
        let write r x next = object (self) 
          method block = !r <> None
          method run   = if self # block then [self]
                         else r := Some x ; [next ()]
        end
        
        let read r next = object (self) 
          method block = !r = None
          method run   = match r with 
                          | None -> [self]
                          | Some x -> r := None ; [next x]
        end
        

        您可以创建更适合您需求的原语,例如在您的频道中添加“传输所需时间”属性。

        下一步是定义模拟引擎。

        (* The simulation engine can be implemented as a simple queue. It starts 
           with a pre-defined set of threads and returns when no threads are left, 
           or when all threads are blocking. *)
        let simulate threads = 
          let q = Queue.create () in 
          let () = List.iter (fun t -> Queue.push t q) threads in 
          let rec loop blocking = 
            if Queue.is_empty q then `AllThreadsTerminated else 
              if Queue.length q = blocking then `AllThreadsBlocked else 
                let thread = Queue.pop q in 
                if thread # block then ( 
                  Queue.push thread q ; 
                  loop (blocking + 1) 
                ) else ( 
                  List.iter (fun t -> Queue.push t q) (thread # run) ; 
                  loop 0
                ) 
          in
          loop 0 
        

        同样,您可以调整引擎以跟踪哪个节点正在执行哪个线程,保持每个节点的优先级以模拟一个节点比其他节点慢得多或快得多,或者随机选择一个线程在每个节点上执行步等。

        最后一步是执行模拟。在这里,我将有两个线程来回发送随机数。

        let rec thread name input output = 
          write output (Random.int 1024) (fun () -> 
            read input (fun value ->
              Printf.printf "%s : %d" name value ; 
              print_newline () ;
              thread name input output
          ))
        
        let a = ref None and b = ref None 
        let _ = simulate [ thread "A -> B" a b ; thread "B -> A" b a ]        
        

        【讨论】:

        • 这是一个很棒的答案,非常鼓舞人心。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-06-20
        • 2018-10-01
        • 2013-04-22
        • 1970-01-01
        • 2022-06-11
        相关资源
        最近更新 更多