我正在尝试实现一个访问某些URL,从中收集新的相对URL并生成报告的搜寻器。我正在尝试使用Crystal光纤和通道同时进行操作,如下所示:
urls = [...] # of String
visited_urls = []
pool_size.times do
spawn do
loop do
url = urls.shift?
break if url.nil?
channel.send(url) if some_condition
end
end
end
# TODO: here the problem!
loop do
url = channel.receive?
break if url.nil? || channel.closed?
visited_urls << url
end
puts visited_urls.inspect
但是这里我有一个问题-无限秒loop
(它调用channel.receive?
直到通道中的最后一个项目,然后等待一条永远不会到达的新消息)。之所以存在问题,是因为我永远不知道频道中实际有多少个项目,所以我不喜欢Crystal lang Guides的Concurency部分中的建议。
因此,当我们不知道该渠道将要存储多少物品并且需要接收多少物品时,也许有一些良好的做法如何使用该渠道?谢谢!
答案 0 :(得分:5)
对此的一种常见解决方案是具有杀死值。作为主数据流的一部分,如下所示:
results = Channel(String|Symbol).new(POOL_SIZE * 2)
POOL_SIZE.times do
spawn do
while has_work?
results.send "some work result"
end
results.send :done
end
end
done_workers = 0
loop do
message = results.receive
if message == :done
done_workers += 1
break if done_workers == POOL_SIZE
elsif message.is_a? String
puts "Got: #{message}"
end
end
或通过辅助渠道来通知事件:
results = Channel(String).new(POOL_SIZE * 2)
done = Channel(Nil).new(POOL_SIZE)
POOL_SIZE.times do
spawn do
while has_work?
results.send "some work result"
end
done.send nil
end
end
done_workers = 0
loop do
select
when message = results.receive
puts "Got: #{message}"
when done.receive
done_workers += 1
break if done_workers == POOL_SIZE
end
end