-
Notifications
You must be signed in to change notification settings - Fork 71
/
Copy pathclient.rb
156 lines (131 loc) · 4.34 KB
/
client.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
require 'openssl'
require 'faraday'
require 'async'
require 'async/barrier'
require 'async/semaphore'
OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE
class TimeIsOverError < StandardError; end
class ResultIsNotEq < StandardError; end
expected_result = "0bbe9ecf251ef4131dd43e1600742cfb"
expected_time = 7
# Есть три типа эндпоинтов API
# Тип A:
# - работает 1 секунду
# - одновременно можно запускать не более трёх
# Тип B:
# - работает 2 секунды
# - одновременно можно запускать не более двух
# Тип C:
# - работает 1 секунду
# - одновременно можно запускать не более одного
#
def a(value)
Thread.new do
puts "https://localhost:9292/a?value=#{value}"
Faraday.get("https://localhost:9292/a?value=#{value}").body
end
end
def b(value)
Thread.new do
puts "https://localhost:9292/b?value=#{value}"
Faraday.get("https://localhost:9292/b?value=#{value}").body
end
end
def c(value)
Thread.new do
puts "https://localhost:9292/c?value=#{value}"
Faraday.get("https://localhost:9292/c?value=#{value}").body
end
end
func_a = proc { |v| a(v) }
func_b = proc { |v| b(v) }
func_c = proc { |v| c(v) }
@result_task_a = []
def start_worker(values, worker, count, result)
barrier = Async::Barrier.new
Async do
semaphore = Async::Semaphore.new(count, parent: barrier)
values.map do |value|
semaphore.async do
result[value] = worker.call(value).value
end
end.map(&:wait)
ensure
barrier.stop
end
end
# Референсное решение, приведённое ниже работает правильно, занимает ~19.5 секунд
# Надо сделать в пределах 7 секунд
def collect_sorted(arr)
arr.sort.join('-')
end
val1 = [11, 12, 13]
val2 = [21, 22, 23]
val3 = [31, 32, 33]
@all_vall_a = [val1, val2, val3]
@all_vall_b = [1, 2, 3]
# канал для метода a
@results_task_a = {}
# канал для метода b
@results_task_b = {}
# канал для метода c
@results_task_c = {}
@threads = []
@threads << Thread.new {
@all_vall_a.each do |v|
start_worker(v, func_a, 3, @results_task_a)
end
}
@threads << Thread.new { start_worker(@all_vall_b, func_b ,2, @results_task_b) }
# тред который наблюдает за каналами и помере того как в них начинают приходить данные, начинает обращатся к ендпоинту `c`
@threads << Thread.new do
index_fetch = 0
exists = []
process = true
while process do
keys = @results_task_b.keys
unless keys.empty?
keys.each do |key|
next if exists.include?(key)
if key == 1
if @results_task_a[11] && @results_task_a[12] && @results_task_a[13]
payload = "#{[@results_task_a[11], @results_task_a[12], @results_task_a[13]].sort.join("-")}-#{@results_task_b[key]}"
start_worker([payload], func_c ,1, @results_task_c)
exists << key
index_fetch += 1
end
elsif key == 2
if @results_task_a[21] && @results_task_a[22] && @results_task_a[23]
payload = "#{[@results_task_a[21], @results_task_a[22], @results_task_a[23]].sort.join("-")}-#{@results_task_b[key]}"
start_worker([payload], func_c ,1, @results_task_c)
exists << key
index_fetch += 1
end
elsif key == 3
if @results_task_a[31] && @results_task_a[32] && @results_task_a[33]
payload = "#{[@results_task_a[31], @results_task_a[32], @results_task_a[33]].sort.join("-")}-#{@results_task_b[key]}"
start_worker([payload], func_c ,1, @results_task_c)
exists << key
index_fetch += 1
end
end
end
end
if index_fetch >= 3
process = false
break
end
end
end
start = Time.now
@threads.map(&:join)
result = a(@results_task_c.values.sort.join("-")).value
time = Time.now - start
puts "FINISHED in #{time}s."
puts "RESULT = #{result}" # 0bbe9ecf251ef4131dd43e1600742cfb
if result != expected_result
raise ResultIsNotEq, "#{result} != #{expected_result}"
end
if time > expected_time
raise TimeIsOverError, "#{time}"
end