如何避免在此代码中连续实例化 Ruby Thread 对象?
How to avoid consecutive instantiation of Ruby Thread object in this code?
直到现在我还没有使用过Thread,但我认为在这种情况下我必须依赖它。我想分别处理 cURL 命令行的 stdout 和 stderr,因为我想将进度指示器(写入 stderr)中的回车 returns 换行:
require "open3"
cmd="curl -b cookie.txt #{url} -L -o -"
Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|
pid = wait_thr.pid
# I have to process stdout and stderr at the same time but
#asyncronously, because stdout gives much more data then the stderr
#stream. I instantiate a Thread object for reading the stderr, otherwise
#"getc" would block the stdout processing loop.
c=nil
line=""
stdout.each_char do |b|
STDOUT.print b
if c==nil then
c=""
thr = Thread.new {
c=stderr.getc
if c=="\r" || c=="\n" then
STDERR.puts line
line=""
else
line<<c
end
c=nil
}
end
#if stderr still holds some output then I process it:
line=""
stderr.each_char do |c|
if c=="\r" || c=="\n" then
STDERR.puts line
line=""
else
line<<c
end
end
exit_status = wait_thr.value.exitstatus
STDERR.puts exit_status
end #popen3
我的问题是如何避免在处理标准输出 (stdout.each_char) 时在每个循环周期创建一个新的 Thread 实例?我觉得很费时间,我想实例化一次,然后使用它的方法,如停止和运行等
一般可以在主线程中处理stdout
、stderr
其中一个,实例化另一个线程处理另一个。这是同时处理多个源的常见做法。
您需要注意多线程上下文中的内存共享。在您的情况下,line
、stderr
在多个线程中共享和修改而没有同步,这将导致不可预测的行为。
在大多数情况下,Ruby 会为您处理行尾。我不太需要在这里手动处理 \r
、\n
。
require "open3"
cmd="curl -b cookie.txt #{url} -L -o -"
Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|
pid = wait_thr.pid
stdout_thread = Thread.new do
# process stdout in another thread
# you can replace this with the logic you want,
# if the following behavior isn't what you want
stdout.each_line do |line|
puts line
end
end
# process stderr in the main thread
stderr.each_line do |line|
STDERR.puts line
end
# wait the stdout processing to be finished.
stdout_thread.join
end
直到现在我还没有使用过Thread,但我认为在这种情况下我必须依赖它。我想分别处理 cURL 命令行的 stdout 和 stderr,因为我想将进度指示器(写入 stderr)中的回车 returns 换行:
require "open3"
cmd="curl -b cookie.txt #{url} -L -o -"
Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|
pid = wait_thr.pid
# I have to process stdout and stderr at the same time but
#asyncronously, because stdout gives much more data then the stderr
#stream. I instantiate a Thread object for reading the stderr, otherwise
#"getc" would block the stdout processing loop.
c=nil
line=""
stdout.each_char do |b|
STDOUT.print b
if c==nil then
c=""
thr = Thread.new {
c=stderr.getc
if c=="\r" || c=="\n" then
STDERR.puts line
line=""
else
line<<c
end
c=nil
}
end
#if stderr still holds some output then I process it:
line=""
stderr.each_char do |c|
if c=="\r" || c=="\n" then
STDERR.puts line
line=""
else
line<<c
end
end
exit_status = wait_thr.value.exitstatus
STDERR.puts exit_status
end #popen3
我的问题是如何避免在处理标准输出 (stdout.each_char) 时在每个循环周期创建一个新的 Thread 实例?我觉得很费时间,我想实例化一次,然后使用它的方法,如停止和运行等
一般可以在主线程中处理stdout
、stderr
其中一个,实例化另一个线程处理另一个。这是同时处理多个源的常见做法。
您需要注意多线程上下文中的内存共享。在您的情况下,line
、stderr
在多个线程中共享和修改而没有同步,这将导致不可预测的行为。
在大多数情况下,Ruby 会为您处理行尾。我不太需要在这里手动处理 \r
、\n
。
require "open3"
cmd="curl -b cookie.txt #{url} -L -o -"
Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|
pid = wait_thr.pid
stdout_thread = Thread.new do
# process stdout in another thread
# you can replace this with the logic you want,
# if the following behavior isn't what you want
stdout.each_line do |line|
puts line
end
end
# process stderr in the main thread
stderr.each_line do |line|
STDERR.puts line
end
# wait the stdout processing to be finished.
stdout_thread.join
end