任务间的异步数据交换

Asynchronous data exchange between tasks

Toit 中的任务”部分的文档表明该语言具有在任务之间进行异步数据交换的功能。如果我理解正确,那么监控包中的两个 classes:ChannelMailbox 提供了这个机会。不幸的是,我没有找到使用这些 classes 的例子,所以我请你至少给出两个任务的实现的最简单的例子:

提前致谢, MK

感谢提问。

这是第一部分的示例,使用 Channel。如果您有用于另一项任务的消息流,此 class 很有用。

import monitor

main:
  // A channel with a backlog of 5 items.  Once the reader is 5 items behind, the
  // writer will block when trying to send.  This helps avoid unbounded memory
  // use by the in-flight messages if messages are being generated faster than
  // they are being consumed.  Decreasing this will tend to reduce throughput,
  // increasing it will increase memory use.
  channel := monitor.Channel 5

  task:: message_generating_task channel
  task:: message_receiving_task channel

/// Normally this could be looking at IO ports, GPIO pins, or perhaps a socket
/// connection.  It could block for some unknown time while doing this.  In this
/// case we just sleep a little to illustrate that the data arrives at random
/// times.
generate_message:
  milliseconds := random 1000
  sleep --ms=milliseconds
  // The message is just a string, but could be any object.
  return "Message creation took $(milliseconds)ms"

message_generating_task channel/monitor.Channel:
  10.repeat:
    message := generate_message
    channel.send message
  channel.send null  // We are done.

/// Normally this could be looking at IO ports, GPIO pins, or perhaps a socket
/// connection.  It could block for some unknown time while doing this.  In this
/// case we just sleep a little to illustrate that the data takes a random
/// amount of time to process.
process_message message:
  milliseconds := random 1000
  sleep --ms=milliseconds
  print message

message_receiving_task channel/monitor.Channel:
  while message := channel.receive:
    process_message message

这里是一个使用邮箱的例子。如果您有一个任务处理请求并响应其他任务,这个 class 很有用。

import monitor

main:
  mailbox := monitor.Mailbox

  task:: client_task 1 mailbox
  task:: client_task 2 mailbox
  task --background:: factorization_task mailbox

/// Normally this could be looking at IO ports, GPIO pins, or perhaps a socket
/// connection.  It could block for some unknown time while doing this.  For
/// this example we just sleep a little to illustrate that the data arrives at
/// random times.
generate_huge_number:
  milliseconds := random 1000
  sleep --ms=milliseconds
  return (random 100) + 1  // Not actually so huge.

client_task task_number mailbox/monitor.Mailbox:
  10.repeat:
    huge := generate_huge_number
    factor := mailbox.send huge  // Send number, wait for result.
    other_factor := huge / factor
    print "task $task_number: $factor * $other_factor == $huge"

// Factorize a number using the quantum computing port.
factorize_number number:
  // TODO: Use actual quantum computing instead of brute-force search.
  for i := number.sqrt.round; i > 1; i--:
    factor := number / i
    if factor * i == number:
      return factor
    // This will yield so the other tasks can run.  In a real application it
    // would be waiting on an IO pin connected to the quantum computing unit.
    sleep --ms=1
  return 1  // 1 is sort-of a factor of all integers.

factorization_task mailbox/monitor.Mailbox:
  // Because this task was started as a background task (see 'main' function),
  // the program does not wait for it to exit so this loop does not need a real
  // exit condition.
  while number := mailbox.receive:
    result := factorize_number number
    mailbox.reply result

我很确定邮箱示例在 3 月底运行良好。我决定现在检查它并得到错误:

  1. 如果是 Console Toit:

    ./web.toit:8:3:错误:参数不匹配:'task' 任务 --background:: factorization_task 邮箱 ^~~~ 编译失败。

  2. 如果是终端:

    microcx@microcx-desktop:~/toit_apps/Hsm/communication$ toit execute mailbox_sample.toit mailbox_sample.toit:8:3:错误:参数不匹配:'task' 任务 --background:: factorization_task 邮箱 ^~~~ 编译失败。

  3. 可能是因为最新的SDK更新了。以防万一:

    Toit 命令行界面: | v1.0.0 | 2021-03-29 |