1

实现该协议需要两个双向通道似乎很奇怪。难道我们不能只使用一个通道并更改服务器循环以提供和接收该单个通道。请注意,这在 Hopac 中是允许的并且没有问题。作业不能在单个同步操作中使用通道向自己发送消息。解释如果只有一个通道而不是单独的 getCh 和 putCh 通道会出现什么问题。提示:考虑有多个客户的情况。

以上来自Hopac 文档。

新用户是否真的希望在旅程的这一点上了解图书馆实施的细节?当文档给出答案而不是提出问题时,我更喜欢它。为什么同时使用单个通道take并且get是一个坏主意的原因是什么?

module HopacExample

open System
open Hopac
open Hopac.Infixes

type Cell<'a> = {
    takeCh : Ch<'a>
    putCh : Ch<'a>
    }

let get c = Ch.take c.takeCh
let put c (x: 'a) = Ch.give c.putCh x

let cell x = Job.delay <| fun () ->
    let c = {takeCh = Ch (); putCh = Ch ()}
    let server x = 
        Alt.choose [
            Ch.take c.putCh
            Ch.give c.takeCh x ^->. x]

    Job.iterateServer x server >>-. c

run <| job {
    let! c = cell 1
    let print () = Job.start (get c >>- fun i -> printf "%i\n" i)
    let put i = Job.start (put c i)
    do! print()
    do! put 2
    do! print()
    do! put 3
    do! print()
    do! put 4
    do! print()
    do! put 5
    do! print()
    do! put 6
    do! print()
    }

Console.ReadKey()
2
3
4
4
5
6
module HopacExample2

open System
open Hopac
open Hopac.Infixes

let get c = Ch.take c
let put c (x: 'a) = Ch.give c x

let cell x = Job.delay <| fun () ->
    let c = Ch ()
    let server x = 
        Alt.choose [
            Ch.take c
            Ch.give c x ^->. x]

    Job.iterateServer x server >>-. c

run <| job {
    let! c = cell 1
    let print () = Job.start (get c >>- fun i -> printf "%i\n" i)
    let put i = Job.start (put c i)
    do! print()
    do! put 2
    do! print()
    do! put 3
    do! print()
    do! put 4
    do! print()
    do! put 5
    do! print()
    do! put 6
    do! print()
    }

Console.ReadKey()
5
5
5
5
5
6

有一些差异,但没有什么我不会归因于并发的变幻莫测。

4

1 回答 1

0

您需要两个通道的原因是强制用户通过服务器。如果您完全删除服务器,您将能够判断仅使用单个通道的问题所在。只需一个通道,客户端就可以绕过服务器并直接相互通信。

module HopacExample2

open System
open Hopac
open Hopac.Infixes

let get c = Ch.take c
let put c (x: 'a) = Ch.give c x

let cell x = 
    let c = Ch ()
    Job.start (put c x) >>-. c

run <| job {
    let! c = cell 1
    let print () = Job.start (get c >>- fun i -> printf "%i\n" i)
    let put i = Job.start (put c i)
    for i=2 to 6 do
        do! print()
        do! put i
    }

Console.ReadKey()
于 2020-06-12T06:23:09.887 回答