我有一个从文件夹中的 XML 文件导入数据的脚本~/xml/
。目前它按顺序运行,但随着导入文件数量的增加,它开始花费太长时间。
我想并行运行脚本的多个副本,但我可以设想两个脚本开始处理同一个文件时会出现问题,考虑到脚本基本上不知道彼此的存在,你将如何解决这个问题?
数据库并发没有问题,因为每个导入文件都用于不同的数据库。
我有一个从文件夹中的 XML 文件导入数据的脚本~/xml/
。目前它按顺序运行,但随着导入文件数量的增加,它开始花费太长时间。
我想并行运行脚本的多个副本,但我可以设想两个脚本开始处理同一个文件时会出现问题,考虑到脚本基本上不知道彼此的存在,你将如何解决这个问题?
数据库并发没有问题,因为每个导入文件都用于不同的数据库。
您在脚本之间没有任何仲裁,或分配工作,您需要它。
您说这些文件适用于不同的数据库。脚本如何知道哪个数据库?你不能预处理排队的文件并通过在名称上附加一些东西来重命名它们吗?或者,有一个脚本来确定哪些数据去哪里,然后将名称传递给执行加载的子脚本?
我会做后者,并且可能会分叉工作,但线程也可以做到。分叉有一些优点,但线程更容易调试。
您没有对系统进行足够的指定,无法为您提供将滑入的代码,但这是使用线程做什么的一般概念:
require 'thread'
file_queue = Queue.new
Dir['./*'].each { |f| file_queue << f }
consumers = []
2.times do |worker|
consumers << Thread.new do
loop do
break if file_queue.empty?
data_file = file_queue.pop
puts "Worker #{ worker } reading #{ data_file }. Queue size: #{ 1 + file_queue.length }\n"
num_lines = 0
File.foreach(data_file) do |li|
num_lines += 1
end
puts "Worker #{ worker } says #{ data_file } contained #{ num_lines } lines.\n"
end
end
end
consumers.each { |c| c.join }
运行后,它会在控制台中显示:
Worker 1 reading ./blank.yaml. Queue size: 28
Worker 0 reading ./build_links_to_test_files.rake. Queue size: 27
Worker 0 says ./build_links_to_test_files.rake contained 68 lines.
Worker 0 reading ./call_cgi.rb. Queue size: 26
Worker 1 says ./blank.yaml contained 3 lines.
Worker 1 reading ./cgi.rb. Queue size: 25
Worker 0 says ./call_cgi.rb contained 11 lines.
Worker 1 says ./cgi.rb contained 10 lines.
Worker 0 reading ./client.rb. Queue size: 24
Worker 1 reading ./curl_test.sh. Queue size: 23
Worker 0 says ./client.rb contained 19 lines.
Worker 0 reading ./curl_test_all_post_vars.sh. Queue size: 22
这已经被削减了,但你明白了。
Ruby 的Queue
类是关键。它就像一个涂有糖霜的数组,它可以仲裁对队列的访问。可以这样想:“消费者”,即线程,在空中放置一个标志来接收访问队列的权限。当获得该权限时,他们可以pop
修改shift
队列。完成后,权限将授予下一个带有标记的线程。
我使用pop
而不是shift
出于深奥的原因,但是,如果您的文件必须按特定顺序加载,请在将它们添加到队列之前对其进行排序,以便设置顺序,然后使用shift
.
我们想存储正在运行的线程数,以便join
以后可以使用它们。这让线程在母脚本结束之前完成它们的任务。