Skip to content

Task 5 #109

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -4,3 +4,4 @@ gem "async"
gem "falcon", "0.44.0" # use different version on your own risk; 0.44.0 worked
gem "sinatra"
gem "faraday"
gem "rspec"
15 changes: 15 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -30,6 +30,7 @@ GEM
fiber-annotation
fiber-local (~> 1.1)
json
diff-lcs (1.6.0)
falcon (0.44.0)
async
async-container (~> 0.17)
@@ -79,6 +80,19 @@ GEM
rack (>= 3.0.0, < 4)
rack-session (2.0.0)
rack (>= 3.0.0)
rspec (3.13.0)
rspec-core (~> 3.13.0)
rspec-expectations (~> 3.13.0)
rspec-mocks (~> 3.13.0)
rspec-core (3.13.3)
rspec-support (~> 3.13.0)
rspec-expectations (3.13.3)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-mocks (3.13.2)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-support (3.13.2)
ruby2_keywords (0.0.5)
samovar (2.3.0)
console (~> 1.0)
@@ -102,6 +116,7 @@ DEPENDENCIES
async
falcon (= 0.44.0)
faraday
rspec
sinatra

BUNDLED WITH
17 changes: 17 additions & 0 deletions case_study.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Case-study оптимизации

## Актуальная проблема
Есть программа, корректно выполняющая свою работу, но очень медленно.

## Формирование метрики
Время выполнения программы должно укладываться в 7 секунд

## Гарантия корректности работы оптимизированной программы
Был написан тест на корректность работы программы, который проверяет, что программа работает корректно и после оптимизации.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


## Вникаем в детали
В программе происходит много долгих запросов к серверу, которые можно выполнять параллельно.
Было принято решение использовать socketry/async для решения задачи.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

йее


## Результаты
В результате проделанной оптимизации удалось улучшить метрику системы с ~19 секунд до ~6 и уложиться в заданный бюджет.
95 changes: 52 additions & 43 deletions client.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
require 'openssl'
require 'faraday'
require 'async'
require 'async/semaphore'

OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE

@@ -13,20 +15,30 @@
# Тип C:
# - работает 1 секунду
# - одновременно можно запускать не более одного
#

A_SEMAPHORE = Async::Semaphore.new(3)
B_SEMAPHORE = Async::Semaphore.new(2)
C_SEMAPHORE = Async::Semaphore.new(1)

def a(value)
puts "https://localhost:9292/a?value=#{value}"
Faraday.get("https://localhost:9292/a?value=#{value}").body
A_SEMAPHORE.acquire do
puts "https://localhost:9292/a?value=#{value}"
Faraday.get("https://localhost:9292/a?value=#{value}").body
end
end

def b(value)
puts "https://localhost:9292/b?value=#{value}"
Faraday.get("https://localhost:9292/b?value=#{value}").body
B_SEMAPHORE.acquire do
puts "https://localhost:9292/b?value=#{value}"
Faraday.get("https://localhost:9292/b?value=#{value}").body
end
end

def c(value)
puts "https://localhost:9292/c?value=#{value}"
Faraday.get("https://localhost:9292/c?value=#{value}").body
C_SEMAPHORE.acquire do
puts "https://localhost:9292/c?value=#{value}"
Faraday.get("https://localhost:9292/c?value=#{value}").body
end
end

# Референсное решение, приведённое ниже работает правильно, занимает ~19.5 секунд
@@ -36,43 +48,40 @@ def collect_sorted(arr)
arr.sort.join('-')
end

start = Time.now

a11 = a(11)
a12 = a(12)
a13 = a(13)
b1 = b(1)

ab1 = "#{collect_sorted([a11, a12, a13])}-#{b1}"
puts "AB1 = #{ab1}"

c1 = c(ab1)
puts "C1 = #{c1}"

a21 = a(21)
a22 = a(22)
a23 = a(23)
b2 = b(2)

ab2 = "#{collect_sorted([a21, a22, a23])}-#{b2}"
puts "AB2 = #{ab2}"

c2 = c(ab2)
puts "C2 = #{c2}"

a31 = a(31)
a32 = a(32)
a33 = a(33)
b3 = b(3)
def a_collection(number)
Sync do |parent|
[1, 2, 3].map do |n|
parent.async do
a("#{number}#{n}")
end
end.map(&:wait)
end
end

ab3 = "#{collect_sorted([a31, a32, a33])}-#{b3}"
puts "AB3 = #{ab3}"
def part(number)
a_collection, b = Sync do |parent|
a_collection = parent.async { a_collection(number) }
b = parent.async { b(number) }
[a_collection, b].map(&:wait)
end

c3 = c(ab3)
puts "C3 = #{c3}"
ab = "#{collect_sorted(a_collection)}-#{b}"
puts "AB#{number} = #{ab}"

c123 = collect_sorted([c1, c2, c3])
result = a(c123)
c = c(ab)
puts "C#{number} = #{c}"
c
end

puts "FINISHED in #{Time.now - start}s."
puts "RESULT = #{result}" # 0bbe9ecf251ef4131dd43e1600742cfb
def run
c_collection = Sync do |parent|
[1, 2, 3].map do |n|
parent.async do
part(n)
end
end.map(&:wait)
end

c123 = collect_sorted(c_collection)
a(c123)
end
24 changes: 24 additions & 0 deletions log.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
https://localhost:9292/a?value=11
https://localhost:9292/a?value=12
https://localhost:9292/a?value=13
https://localhost:9292/b?value=1
https://localhost:9292/b?value=2
https://localhost:9292/a?value=21
https://localhost:9292/a?value=22
https://localhost:9292/a?value=23
https://localhost:9292/b?value=3
AB1 = 6512bd43d9caa6e02c990b0a82652dca-c20ad4d76fe97759aa27a0c99bff6710-c51ce410c124a10e0db5e4b97fc2af39-6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b
https://localhost:9292/c?value=6512bd43d9caa6e02c990b0a82652dca-c20ad4d76fe97759aa27a0c99bff6710-c51ce410c124a10e0db5e4b97fc2af39-6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b
https://localhost:9292/a?value=31
https://localhost:9292/a?value=32
https://localhost:9292/a?value=33
AB2 = 37693cfc748049e45d87b8c7d8b9aacd-3c59dc048e8850243be8079a5c74d079-b6d767d2f8ed5d21a44b0e5886680cb9-d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35
https://localhost:9292/c?value=37693cfc748049e45d87b8c7d8b9aacd-3c59dc048e8850243be8079a5c74d079-b6d767d2f8ed5d21a44b0e5886680cb9-d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35
C1 = ee54918569d9620a4947a184c097ab1a90b33db6b8a009e01cbbe7238f800ecf846068a36ac7ae289a0796face8b471dcfd7e7d55f9081bccd8f2f50c1d4f888
AB3 = 182be0c5cdcd5072bb1864cdee4d3d6e-6364d3f0f495b6ab9dcf8d3b5c6e0b01-c16a5320fa475530d9583c34fd356ef5-4e07408562bedb8b60ce05c1decfe3ad16b72230967de01f640b7e4729b49fce
https://localhost:9292/c?value=182be0c5cdcd5072bb1864cdee4d3d6e-6364d3f0f495b6ab9dcf8d3b5c6e0b01-c16a5320fa475530d9583c34fd356ef5-4e07408562bedb8b60ce05c1decfe3ad16b72230967de01f640b7e4729b49fce
C2 = 4bc5a33ec7c74626144b5277e887501074b07819ecd9cc506b08e765be1f26a3d7c9fbb59bde46379ca7f0ebf2ef066f38c0a4652d4017a635fc8bdddc070557
C3 = 35bf8dfb6c327259fd05a56a6d47ecfc21965b0f4ff8926b164c32e31cc91d825da1a73bc145cdec04dfbb0862fb14b687f15a8233be15092c4c85da4b7bf94a
https://localhost:9292/a?value=35bf8dfb6c327259fd05a56a6d47ecfc21965b0f4ff8926b164c32e31cc91d825da1a73bc145cdec04dfbb0862fb14b687f15a8233be15092c4c85da4b7bf94a-4bc5a33ec7c74626144b5277e887501074b07819ecd9cc506b08e765be1f26a3d7c9fbb59bde46379ca7f0ebf2ef066f38c0a4652d4017a635fc8bdddc070557-ee54918569d9620a4947a184c097ab1a90b33db6b8a009e01cbbe7238f800ecf846068a36ac7ae289a0796face8b471dcfd7e7d55f9081bccd8f2f50c1d4f888
FINISHED in 6.05257s.
RESULT = 0bbe9ecf251ef4131dd43e1600742cfb
29 changes: 29 additions & 0 deletions rspec/client_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
require 'rspec'
require 'sinatra/base'
require_relative '../client'

RSpec.describe 'Client' do
before do
allow(Faraday).to receive(:get).with(any_args) do |*args, **_kwargs|
uri = URI.parse(args[0])
path = uri.path
value = CGI.parse(uri.query)['value'].first

result = case path
when '/a'
Digest::MD5.hexdigest(value)
when '/b'
Digest::SHA256.hexdigest(value)
when '/c'
Digest::SHA512.hexdigest(value)
end

instance_double(Faraday::Response,
status: 200,
body: result,
headers: {'Content-Type' => 'application/json'})
end
end

it { expect(run).to eq '0bbe9ecf251ef4131dd43e1600742cfb' }
end
10 changes: 10 additions & 0 deletions runner.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
require_relative 'client'

$stdout = File.open('log.txt', 'w')

start = Time.now

result = run

puts "FINISHED in #{Time.now - start}s."
puts "RESULT = #{result}" # 0bbe9ecf251ef4131dd43e1600742cfb