Last active
October 12, 2018 21:42
-
-
Save kopylovvlad/22700acbc79a33ba6c84bf102a455671 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'time' | |
# thread pool class | |
# it takes pool size | |
class ThreadPool | |
attr_reader :result, :number, :size | |
def initialize(size) | |
@finish = false | |
@result = nil | |
@number = nil | |
@size = size | |
@jobs = Queue.new | |
@pool = init_pool | |
end | |
def finish? | |
@finish | |
end | |
def finish!(result, number) | |
@finish = true | |
@result = result | |
@number = number | |
@jobs = [[ Proc.new {}, nil]] | |
end | |
def jobs_size | |
@jobs.size | |
end | |
# add a job to queue | |
def schedule(*args, &block) | |
@jobs << [block, args] | |
end | |
def clear! | |
@jobs = [] | |
end | |
# run threads and perform jobs from queue | |
def run! | |
@size.times do | |
schedule { throw :exit } | |
end | |
@pool.map(&:join) | |
end | |
private | |
def init_pool | |
Array.new(size) do | |
Thread.new do | |
catch(:exit) do | |
loop do | |
job, args = @jobs.pop | |
job.call(*args) | |
break if @jobs.size == 0 | |
end | |
end | |
end | |
end | |
end | |
end | |
module HashGenerator | |
# calculating hash for string "#{string}#{number}" | |
def self.call(string, number) | |
# for macOS | |
return `echo '#{string}#{number}' | sha2 -256` | |
.gsub('SHA-256 ((null)) = ', '') | |
.gsub(/\n/, '') | |
# for Linux | |
# return `echo '#{string}#{number}' | sha256sum`.gsub(/\s\s\-$/, '') | |
end | |
end | |
module HashChecker | |
# check does hash start with corrent numbers | |
def self.call(hash_str, zero_count) | |
hash_start = hash_str[0..(zero_count - 1)] | |
hash_start == ('0' * zero_count) | |
end | |
end | |
module TimeSplitter | |
# prepare time format for output | |
def self.call(time_start, time_end) | |
seconds = ((time_end - time_start)).round | |
minutes = ((time_end - time_start) / 60).round | |
[minutes, seconds] | |
end | |
end | |
class MainMachine | |
attr_reader :main_string, :zero_count, :thread_count, :query_limit | |
def initialize(main_string, zero_count, thread_count) | |
@main_string = main_string | |
@zero_count = zero_count | |
@thread_count = thread_count | |
@query_limit = 1_000_000 | |
@pool = ThreadPool.new(thread_count) | |
end | |
def perform | |
time_start = Time.now | |
# step 1: fill query from 1 to 1_000_000 | |
fill_queue | |
# step 2: run all jobs | |
run_jobs | |
time_end = Time.now | |
# output result | |
if @pool.finish? | |
minutes, seconds = TimeSplitter.call(time_start, time_end) | |
puts "\n\rstring: '#{main_string}'" | |
puts "number: '#{@pool.number}'" | |
puts "hash: '#{@pool.result}'" | |
puts "time: '#{minutes}'(minutes), '#{seconds}'(seconds)" | |
else | |
puts "\n\r we did not calculate it" | |
puts "please, run again with new limit" | |
end | |
end | |
private | |
def fill_queue | |
number = 0 | |
loop do | |
dublicate_number = number.to_s.dup.to_i | |
@pool.schedule do | |
# generate hash | |
sha_hash = HashGenerator.call(main_string, dublicate_number) | |
# check is hash valid | |
if HashChecker.call(sha_hash, zero_count) == true | |
@pool.finish!(sha_hash, dublicate_number) | |
end | |
end | |
break if number == query_limit | |
number += 1 | |
end | |
end | |
def run_jobs | |
@pool.run! | |
loop do | |
break if @pool.finish? || @pool.jobs_size == 0 | |
end | |
@pool.clear! | |
end | |
end | |
main_string = 'hello world!' | |
number_of_leading_zeros = 3 | |
thread_count = 10 | |
MainMachine.new(main_string, number_of_leading_zeros, thread_count).perform |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment