【问题标题】:How to create multiple Threads in OCaml如何在 OCaml 中创建多个线程
【发布时间】:2022-08-06 08:40:05
【问题描述】:

函数run_counter 可以创建 m 个线程,每个线程从 0 计数到 n:

let run_counters m n = 
            let rec count x = 
              if x > n then ()
              else ( Printf.printf \"%d\" x;
            Thread.yield ();
            count (x+1) ) 
            in 
            Thread.create count 0

但是我不知道如何创建多个线程,我尝试使用计数器 m 编写递归调用,但出现错误:This expression has type t but an expression was expected of type unit

let run_counters m n = 
            let rec count x = 
              if x > n then ()
              else ( Printf.printf \"%d\" x;
            Thread.yield ();
            count (x+1) ) 
            in 
            let rec inc n =
            if n = 0 then () else
            inc (n-1);
            Thread.create count 0; 
        
  • 错误信息是什么?
  • 此外,您的代码格式非常糟糕,很容易导致掩盖错误。你应该考虑使用像 ocp-indent 或 ocamlformat 这样的工具来自动格式化代码,如果你不想手动这样做的话。
  • 你能显示确切的错误吗?它应该告诉你哪个表达式是错误的。
  • 顺便说一句,当我添加您的代码时,我遇到了语法错误

标签: multithreading parallel-processing functional-programming ocaml


【解决方案1】:

好的,所以你的函数有点乱,首先有一个语法错误:

let run_counters m n = 
            let rec count x = 
              if x > n then ()
              else ( Printf.printf "%d" x;
            Thread.yield ();
            count (x+1) ) 
            in 
            let rec inc n =
            if n = 0 then () else
    >>>>>   inc (n-1);
            Thread.create count 0; 
        

在位置>>>>>,有一个let rec inc...,后面没有in ...,你只需用分号打断表达式。如果我们用in 替换它,那么函数inc 被报告为未使用。

让我们退后一步,分别编写每个函数,这将比尝试一次完成所有事情容易得多。此外,您可以更轻松地测试各个功能。

做某事n

首先,编写一个函数,调用某个函数f 来处理它的副作用,n 次。我们可以编写一个递归版本(如果这是家庭作业,你可能会被要求这样做),但是 OCaml 有 for 循环,所以让我们使用它们:

let rec call_n_times f n =
  for i = 0 to (n-1) do
    f i
  done

例如,这打印从 0 到 2 的数字,并且不返回任何内容(单位类型):

# call_n_times (fun n -> Printf.printf "%d\n" n) 3;;
0
1
2
- : unit = ()

事实上,这个例子是你的线程应该做的(多么巧合)。

打印递增的数字

在我们未来的测试中,我们将调用不同的计数器,所以让我们添加一个参数,它是计数器的名称:

# let print_n name = call_n_times (fun i -> Printf.printf "%s %d\n" name i);;
val print_n : string -> int -> unit = <fun>

如您所见,我们将call_n_times 的部分应用命名为print_n 与一个函数,其余参数n 在这里是隐式的。

# print_n "test" 3;;
test: 0
test: 1
test: 2

产生 1 个线程

下一步是编写一个只生成一个线程的函数,并要求它使用线程名称执行print_n(因此它需要一个整数参数)。

像以前一样使用部分应用程序,这是:

# let spawn_counter name = Thread.create (print_n name);;
val spawn_counter : string -> int -> Thread.t = <fun>

例如:

# spawn_counter "single-thread" 3;;
- : Thread.t = <abstr>

# Thread.yield();;
single-thread: 0
single-thread: 1
single-thread: 2
- : unit = ()

用数字命名线程

我们还需要一个从数字生成名称(字符串)的中间函数,让我们快速编写:

# let thread_name = Printf.sprintf "<thread %d>";;
val thread_name : int -> string = <fun>

产生m线程

现在我们可以写spawn_m_n_counters

# let spawn_m_n_counters m n =
    call_n_times (fun i -> spawn_counter (thread_name i) n) m;;
val spawn_m_n_counters : int -> int -> unit = <fun>

# spawn_m_n_counters 3 5;;
- : unit = ()

重构

你有你的函数的基本骨架,但我把Thread.yield() 排除在函数之外。

另外,你想搜集所有生成线程,以便您可以join 他们。这意味着您需要一个收集函数输出的call_n_times。看看你是否可以递归地写。

【讨论】:

    猜你喜欢
    • 2023-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-18
    • 1970-01-01
    相关资源
    最近更新 更多