From c2496c6866f601ee615895336ff29801419455c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D0=BD=D0=B0=20=D0=91=D1=83=D1=8F=D0=BD=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0?= Date: Wed, 26 Feb 2025 22:00:25 +0300 Subject: [PATCH 1/6] Started using threads --- client_threads.rb | 72 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 client_threads.rb diff --git a/client_threads.rb b/client_threads.rb new file mode 100644 index 0000000..8944aab --- /dev/null +++ b/client_threads.rb @@ -0,0 +1,72 @@ +require 'openssl' +require 'faraday' + +OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE + +# Есть три типа эндпоинтов API +# Тип A: +# - работает 1 секунду +# - одновременно можно запускать не более трёх +# Тип B: +# - работает 2 секунды +# - одновременно можно запускать не более двух +# Тип C: +# - работает 1 секунду +# - одновременно можно запускать не более одного +# +def a(value) + puts "https://localhost:9292/a?value=#{value}" + Faraday.get("https://localhost:9292/a?value=#{value}").body +end + +def b(value) + puts "https://localhost:9292/b?value=#{value}" + Faraday.get("https://localhost:9292/b?value=#{value}").body +end + +def c(value) + puts "https://localhost:9292/c?value=#{value}" + Faraday.get("https://localhost:9292/c?value=#{value}").body +end + +# Референсное решение, приведённое ниже работает правильно, занимает ~19.5 секунд +# Надо сделать в пределах 7 секунд + +def collect_sorted(arr) + arr.sort.join('-') +end + +start = Time.now + +res = [Thread.new { a(11) }, Thread.new { a(12) }, Thread.new { a(13) }, Thread.new { b(1) }].map(&:value) +b1 = res.pop + +ab1 = "#{collect_sorted(res)}-#{b1}" +puts "AB1 = #{ab1}" + +res = [Thread.new { a(21) }, Thread.new { a(22) }, Thread.new { a(23) }, Thread.new { b(2) }].map(&:value) +b2 = res.pop + +ab2 = "#{collect_sorted(res)}-#{b2}" +puts "AB2 = #{ab2}" + +res = [Thread.new { a(31) }, Thread.new { a(32) }, Thread.new { a(33) }, Thread.new { b(3) }].map(&:value) + +b3 = res.pop + +ab3 = "#{collect_sorted(res)}-#{b3}" +puts "AB3 = #{ab3}" + +# find c-s +c1 = c(ab1) +puts "C1 = #{c1}" +c2 = c(ab2) +puts "C2 = #{c2}" +c3 = c(ab3) +puts "C3 = #{c3}" + +c123 = collect_sorted([c1, c2, c3]) +result = a(c123) + +puts "FINISHED in #{Time.now - start}s." +puts "RESULT = #{result}" # 0bbe9ecf251ef4131dd43e1600742cfb From de85fd3c139202d60eed2467b7272c1121c022a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D0=BD=D0=B0=20=D0=91=D1=83=D1=8F=D0=BD=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0?= Date: Wed, 26 Feb 2025 22:18:16 +0300 Subject: [PATCH 2/6] Parallel execution in ~7 seconds --- client_threads.rb | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/client_threads.rb b/client_threads.rb index 8944aab..54d57f1 100644 --- a/client_threads.rb +++ b/client_threads.rb @@ -38,30 +38,28 @@ def collect_sorted(arr) start = Time.now -res = [Thread.new { a(11) }, Thread.new { a(12) }, Thread.new { a(13) }, Thread.new { b(1) }].map(&:value) +res = [Thread.new { a(11) }, Thread.new { a(12) }, Thread.new { a(13) }, Thread.new { b(1) }, Thread.new { b(2) }].map(&:value) +b2 = res.pop b1 = res.pop ab1 = "#{collect_sorted(res)}-#{b1}" puts "AB1 = #{ab1}" -res = [Thread.new { a(21) }, Thread.new { a(22) }, Thread.new { a(23) }, Thread.new { b(2) }].map(&:value) -b2 = res.pop +res = [Thread.new { a(21) }, Thread.new { a(22) }, Thread.new { a(23) }, Thread.new { c(ab1) }].map(&:value) +c1 = res.pop +puts "C1 = #{c1}" ab2 = "#{collect_sorted(res)}-#{b2}" puts "AB2 = #{ab2}" -res = [Thread.new { a(31) }, Thread.new { a(32) }, Thread.new { a(33) }, Thread.new { b(3) }].map(&:value) - +res = [Thread.new { a(31) }, Thread.new { a(32) }, Thread.new { a(33) }, Thread.new { b(3) }, Thread.new { c(ab2) }].map(&:value) +c2 = res.pop +puts "C2 = #{c2}" b3 = res.pop ab3 = "#{collect_sorted(res)}-#{b3}" puts "AB3 = #{ab3}" -# find c-s -c1 = c(ab1) -puts "C1 = #{c1}" -c2 = c(ab2) -puts "C2 = #{c2}" c3 = c(ab3) puts "C3 = #{c3}" From 7ba08f8be708736ad24ae331e0f0b6f15bc548d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D0=BD=D0=B0=20=D0=91=D1=83=D1=8F=D0=BD=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0?= Date: Wed, 26 Feb 2025 22:20:45 +0300 Subject: [PATCH 3/6] Seconds comments --- client_threads.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/client_threads.rb b/client_threads.rb index 54d57f1..99c3753 100644 --- a/client_threads.rb +++ b/client_threads.rb @@ -38,6 +38,7 @@ def collect_sorted(arr) start = Time.now +# 3*a + 2*b (2s) res = [Thread.new { a(11) }, Thread.new { a(12) }, Thread.new { a(13) }, Thread.new { b(1) }, Thread.new { b(2) }].map(&:value) b2 = res.pop b1 = res.pop @@ -45,6 +46,7 @@ def collect_sorted(arr) ab1 = "#{collect_sorted(res)}-#{b1}" puts "AB1 = #{ab1}" +# 3*a + c (1s) res = [Thread.new { a(21) }, Thread.new { a(22) }, Thread.new { a(23) }, Thread.new { c(ab1) }].map(&:value) c1 = res.pop puts "C1 = #{c1}" @@ -52,6 +54,7 @@ def collect_sorted(arr) ab2 = "#{collect_sorted(res)}-#{b2}" puts "AB2 = #{ab2}" +# 3*a + b + c (2s) res = [Thread.new { a(31) }, Thread.new { a(32) }, Thread.new { a(33) }, Thread.new { b(3) }, Thread.new { c(ab2) }].map(&:value) c2 = res.pop puts "C2 = #{c2}" @@ -60,10 +63,12 @@ def collect_sorted(arr) ab3 = "#{collect_sorted(res)}-#{b3}" puts "AB3 = #{ab3}" +# 1s c3 = c(ab3) puts "C3 = #{c3}" c123 = collect_sorted([c1, c2, c3]) +# 1s result = a(c123) puts "FINISHED in #{Time.now - start}s." From df7f42077bf1a793e76ea2deac614b921be44b20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D0=BD=D0=B0=20=D0=91=D1=83=D1=8F=D0=BD=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0?= Date: Fri, 28 Feb 2025 09:03:17 +0300 Subject: [PATCH 4/6] Collect b3 a bit earlier --- client_threads.rb | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/client_threads.rb b/client_threads.rb index 99c3753..a5007f9 100644 --- a/client_threads.rb +++ b/client_threads.rb @@ -46,19 +46,20 @@ def collect_sorted(arr) ab1 = "#{collect_sorted(res)}-#{b1}" puts "AB1 = #{ab1}" -# 3*a + c (1s) -res = [Thread.new { a(21) }, Thread.new { a(22) }, Thread.new { a(23) }, Thread.new { c(ab1) }].map(&:value) +# 3*a + b + c (2s) +res = [Thread.new { a(21) }, Thread.new { a(22) }, Thread.new { a(23) }, Thread.new { b(3) }, Thread.new { c(ab1) }].map(&:value) c1 = res.pop puts "C1 = #{c1}" +b3 = res.pop + ab2 = "#{collect_sorted(res)}-#{b2}" puts "AB2 = #{ab2}" -# 3*a + b + c (2s) -res = [Thread.new { a(31) }, Thread.new { a(32) }, Thread.new { a(33) }, Thread.new { b(3) }, Thread.new { c(ab2) }].map(&:value) +# 3*a + c (1s) +res = [Thread.new { a(31) }, Thread.new { a(32) }, Thread.new { a(33) }, Thread.new { c(ab2) }].map(&:value) c2 = res.pop puts "C2 = #{c2}" -b3 = res.pop ab3 = "#{collect_sorted(res)}-#{b3}" puts "AB3 = #{ab3}" From 485303287d9a9076211db8bb766dd8b0dab9e8a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D0=BD=D0=B0=20=D0=91=D1=83=D1=8F=D0=BD=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0?= Date: Fri, 28 Feb 2025 21:17:33 +0300 Subject: [PATCH 5/6] Improve parallelizing threads --- client_threads.rb | 66 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 48 insertions(+), 18 deletions(-) diff --git a/client_threads.rb b/client_threads.rb index a5007f9..cb06c8c 100644 --- a/client_threads.rb +++ b/client_threads.rb @@ -39,38 +39,68 @@ def collect_sorted(arr) start = Time.now # 3*a + 2*b (2s) -res = [Thread.new { a(11) }, Thread.new { a(12) }, Thread.new { a(13) }, Thread.new { b(1) }, Thread.new { b(2) }].map(&:value) -b2 = res.pop -b1 = res.pop +as = [] +bs = [] -ab1 = "#{collect_sorted(res)}-#{b1}" -puts "AB1 = #{ab1}" +a_threads = [] +b_threads = [] -# 3*a + b + c (2s) -res = [Thread.new { a(21) }, Thread.new { a(22) }, Thread.new { a(23) }, Thread.new { b(3) }, Thread.new { c(ab1) }].map(&:value) -c1 = res.pop -puts "C1 = #{c1}" -b3 = res.pop +[11, 12, 13].each do |i| + a_threads << Thread.new { as << a(i) } +end +[1, 2].each do |i| + b_threads << Thread.new { bs << b(i) } +end + +# Ждем a(11), a(12), a(13) +a_threads.each(&:join) -ab2 = "#{collect_sorted(res)}-#{b2}" +# Запускаем a(21), a(22), a(23) после завершения a(11), a(12), a(13) +[21, 22, 23].each do |i| + b_threads << Thread.new { as << a(i) } +end + +# Ждем завершения всех потоков +b_threads.each(&:join) # 2s + +ab1 = "#{collect_sorted(as[0,3])}-#{bs[0]}" +puts "AB1 = #{ab1}" + +ab2 = "#{collect_sorted(as[3,3])}-#{bs[1]}" puts "AB2 = #{ab2}" -# 3*a + c (1s) -res = [Thread.new { a(31) }, Thread.new { a(32) }, Thread.new { a(33) }, Thread.new { c(ab2) }].map(&:value) -c2 = res.pop -puts "C2 = #{c2}" +as = [] +b3 = nil +c1 = nil +c2 = nil -ab3 = "#{collect_sorted(res)}-#{b3}" +ab_threads = [] + +[31, 32, 33].each do |i| + ab_threads << Thread.new { as << a(i) } +end + +ab_threads << Thread.new { b3 = b(3) } + +Thread.new { c1 = c(ab1) }.join +Thread.new { c2 = c(ab2) }.join + +ab_threads.each(&:join) # 2s + +puts "C1 = #{c1}" + +ab3 = "#{collect_sorted(as)}-#{b3}" puts "AB3 = #{ab3}" +puts "C2 = #{c2}" + # 1s c3 = c(ab3) puts "C3 = #{c3}" c123 = collect_sorted([c1, c2, c3]) -# 1s -result = a(c123) +result = a(c123) # 1s puts "FINISHED in #{Time.now - start}s." puts "RESULT = #{result}" # 0bbe9ecf251ef4131dd43e1600742cfb From 1a87c742392e75deadf782047e5ae7611933ddfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D0=BD=D0=B0=20=D0=91=D1=83=D1=8F=D0=BD=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0?= Date: Sat, 1 Mar 2025 23:32:53 +0300 Subject: [PATCH 6/6] Parallelize with socketry/async --- client_async.rb | 116 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 client_async.rb diff --git a/client_async.rb b/client_async.rb new file mode 100644 index 0000000..4c5413b --- /dev/null +++ b/client_async.rb @@ -0,0 +1,116 @@ +require 'openssl' +require 'faraday' +require 'async' +require 'async/barrier' +require 'async/semaphore' + +OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE + +# Есть три типа эндпоинтов API +# Тип A: +# - работает 1 секунду +# - одновременно можно запускать не более трёх +# Тип B: +# - работает 2 секунды +# - одновременно можно запускать не более двух +# Тип C: +# - работает 1 секунду +# - одновременно можно запускать не более одного +# +def a(value) + puts "https://localhost:9292/a?value=#{value}" + Faraday.get("https://localhost:9292/a?value=#{value}").body +end + +def b(value) + puts "https://localhost:9292/b?value=#{value}" + Faraday.get("https://localhost:9292/b?value=#{value}").body +end + +def c(value) + puts "https://localhost:9292/c?value=#{value}" + Faraday.get("https://localhost:9292/c?value=#{value}").body +end + +# Референсное решение, приведённое ниже работает правильно, занимает ~19.5 секунд +# Надо сделать в пределах 7 секунд + +def collect_sorted(arr) + arr.sort.join('-') +end + +start = Time.now + +barrier = Async::Barrier.new + +a_semaphore = Async::Semaphore.new(3, parent: barrier) +b_semaphore = Async::Semaphore.new(2, parent: barrier) +c_semaphore = Async::Semaphore.new(1, parent: barrier) + +as = [] +bs = [] + +# 2s +Async do + [1, 2].each do |i| + b_semaphore.async(parent: barrier) do + bs << b(i) + end + end + + [11, 12, 13, 21, 22, 23].each do |i| + a_semaphore.async(parent: barrier) do + as << a(i) + end + end + + # Wait until all jobs are done: + barrier.wait +end + +ab1 = "#{collect_sorted(as[0,3])}-#{bs[0]}" +puts "AB1 = #{ab1}" + +ab2 = "#{collect_sorted(as[3,3])}-#{bs[1]}" +puts "AB2 = #{ab2}" + +as = [] +b3 = nil +c1 = nil +c2 = nil + +# 2s +Async do + b_semaphore.async(parent: barrier) do + b3 = b(3) + end + + [31, 32, 33].each do |i| + a_semaphore.async(parent: barrier) do + as << a(i) + end + end + + c_semaphore.async(parent: barrier) do + c1 = c(ab1) + c2 = c(ab2) + end + # Wait until all jobs are done: + barrier.wait +end + +puts "C1 = #{c1}" +puts "C2 = #{c2}" +ab3 = "#{collect_sorted(as)}-#{b3}" +puts "AB3 = #{ab3}" + +# 1s +c3 = c(ab3) +puts "C3 = #{c3}" + +c123 = collect_sorted([c1, c2, c3]) +# 1s +result = a(c123) + +puts "FINISHED in #{Time.now - start}s." +puts "RESULT = #{result}" # 0bbe9ecf251ef4131dd43e1600742cfb