Reputation: 10134
I am writing a program that will perform a number of checks and output the results via puts
. I want to speed up this process using threads. However, the output includes inconsistent new lines.
How can I cleanup this output?
Ex.
> (1..99).each_with_object([]) {|i, threads| threads << Thread.new {sleep(rand 2) && puts(i)} }.each(&:join)
7
202535
36605562
7882
8959958
2826
29
433941
445258
69728063
777975
85496
22
14
24
3850
9712
9892
47
40
71
84
94
49
1
2
152187131627234218194531535759
305417
34647448
735111
66684676
838137
6133
679093
917099
3
56
32
10
6
88
86
65
Upvotes: 0
Views: 752
Reputation: 798
Updated with the Tin Man's comment
Use print
/printf
or puts
and provide the new-line char \n
explicitly (since puts
may write the new-line separately from the rest and other threads may jumping in).
(1..99).each_with_object([]) {|i, threads| threads << Thread.new {sleep(rand 2) && print("#{i}\n") } }.each(&:join)
Upvotes: 1
Reputation: 22325
Your threads are all sharing a resource: stdout. Whenever you have threads sharing a resource you need to make sure that you don't have more than one accessing that resource at a time, otherwise you get interference as you have observed.
Here are two approaches to solving this. First, you can change the threads to just return a value, then do all the printing afterwards:
threads = (1..99).map {|i| Thread.new { sleep(rand 2) && i } }
threads.each do |t|
t.join
puts t.value
end
This is a good approach if your threads all run at about the same speed since it will hang on the slowest thread (even if other faster threads have finished).
Alternatively, use a mutex to protect stdout.
mutex = Thread::Mutex.new
(1..99).map do |i|
Thread.new { sleep(rand 2); mutex.synchronize { puts i } }
end.each(&:join)
This will let each thread run and print independently. But it's not so good if you need each thread to do a lot of printing: the more they fight over the mutex the slower your threads will get.
Upvotes: 0