Crystal将Thread Pool背后的想法转换为Fibers / spawn

时间:2015-06-15 19:34:44

标签: multithreading coroutine crystal-lang

我很难学习Fibers \ coroutines背后的想法以及Crystal中的实现。

我希望这是一个正确的地方,我会完全接受一个"不在这里"回答:)

这是我在Ruby中处理多线程的常用方法:

=IF(AND(ISERROR(FIND("ø";B2));ISERROR(FIND(CHAR(34);B2)));B2;IF(ISERROR(FIND("ø";B2));LEFT(B2;FIND(CHAR(34);B2)-1); LEFT(B2; FIND("ø";B2)-1)))

这样我打开一个新线程,通常是传入连接或其他东西,将线程添加到线程数组,然后检查我没有更多线程,然后我想要的。

使用spawn \ channels \ fiber等在Crystal中实现类似的东西会有什么好方法。?

2 个答案:

答案 0 :(得分:14)

这样的事情:

require "socket"

ch = Channel(TCPSocket).new

10.times do
  spawn do
    loop do
      socket = ch.receive
      socket.puts "Hi!"
      socket.close
    end
  end
end

server = TCPServer.new(1234)
loop do
  socket = server.accept
  ch.send socket
end

此代码将预生成10根光纤以参加请求。该通道是无缓冲的,因此如果它们不能被任何光纤接收,则连接将不会排队。

答案 1 :(得分:6)

您无法复制其对线程的工作方式。 spawn不会返回协程对象,并且无法join协程。

然而,我们可以在协同程序和池管理器之间建立通道。这个经理可以在它自己的协程中运行,也可以作为主协程 - 这将阻止进程退出。

这是一个工作示例,使用worker(&block)方法生成协程,并打开通道以返回其状态(失败或终止),以及将保留的pool(&block)方法一群这样的工人,从结果渠道中读取以了解协同程序的状态,并继续产生新的协同程序。

def worker(&block)
  result = UnbufferedChannel(Exception?).new

  ::spawn do
    begin
      block.call
    rescue ex
      result.send(ex)
    else
      result.send(nil)
    end
  end

  result
end

def pool(size, &block)
  counter = 0
  results = [] of UnbufferedChannel(Exception?)

  loop do
    while counter < size
      counter += 1
      puts "spawning worker"
      results << worker(&block)
    end

    result = Channel.select(results)
    counter -= 1
    results.delete(result)

    if ex = result.receive
      puts "ERROR: #{ex.message}"
    else
      puts "worker terminated"
    end
  end
end

pool(5) do
  loop { helper_method(1, 2, 3, 4) }
end