From d64c12f9240be07f8fa33bef288d0c9a64bc8186 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Rudowicz?= Date: Sat, 28 Nov 2020 21:43:02 +0100 Subject: [PATCH] map_parallel --- spec/gmi_renderer_spec.cr | 1 + spec/map_parallel_spec.cr | 21 +++++++++++++++++++++ spec/spec_helper.cr | 1 - src/main.cr | 26 ++++++++++---------------- src/map_parallel.cr | 15 +++++++++++++++ 5 files changed, 47 insertions(+), 17 deletions(-) create mode 100644 spec/map_parallel_spec.cr create mode 100644 src/map_parallel.cr diff --git a/spec/gmi_renderer_spec.cr b/spec/gmi_renderer_spec.cr index 4632f3e..95a2e91 100644 --- a/spec/gmi_renderer_spec.cr +++ b/spec/gmi_renderer_spec.cr @@ -1,4 +1,5 @@ require "./spec_helper" +require "../src/gmi_renderer.cr" def render_to_gmi(input : String) GmiRenderer.new.render(Markd::Parser.parse(input)) diff --git a/spec/map_parallel_spec.cr b/spec/map_parallel_spec.cr new file mode 100644 index 0000000..f8ba039 --- /dev/null +++ b/spec/map_parallel_spec.cr @@ -0,0 +1,21 @@ +require "benchmark" + +require "./spec_helper" +require "../src/map_parallel" + +describe "MapParallel" do + it "has the same output effect as simple map" do + input = (0..5000) + + input.map_parallel { |x| x + 1 }.should eq(input.map { |x| x + 1 }) + end + + it "should be faster than running all blocks serially" do + ts = Time::Span.new(nanoseconds: 10_000) + executions = 5000 + input = (0..executions) + + Benchmark.realtime { input.map_parallel { |x| sleep(ts) } } + .should be < (ts*executions*0.5) + end +end diff --git a/spec/spec_helper.cr b/spec/spec_helper.cr index 4593745..e2f4f80 100644 --- a/spec/spec_helper.cr +++ b/spec/spec_helper.cr @@ -1,2 +1 @@ require "spec" -require "../src/gmi_renderer.cr" diff --git a/src/main.cr b/src/main.cr index 86efe9d..f948541 100644 --- a/src/main.cr +++ b/src/main.cr @@ -1,24 +1,18 @@ require "markd" require "./gmi_renderer" - -wait = Channel(Nil).new - -files_to_process = 0 +require "./map_parallel" Dir.new(".").entries .select! { |x| /\.md$/ =~ x } .tap { |x| files_to_process = x.size } - .each do |fname| - spawn do - rendered = GmiRenderer.new.render( - Markd::Parser.parse( - File.read(fname) - ) + .map_parallel do |fname| + {fname, GmiRenderer.new.render( + Markd::Parser.parse( + File.read(fname) ) - puts "======= #{fname} =======\n" - puts "#{rendered}\n" - wait.send(nil) - end + )} + end + .each do |fname, rendered| + puts "======= #{fname} =======\n" + puts "#{rendered}\n" end - -files_to_process.times { wait.receive } diff --git a/src/map_parallel.cr b/src/map_parallel.cr new file mode 100644 index 0000000..655aba7 --- /dev/null +++ b/src/map_parallel.cr @@ -0,0 +1,15 @@ +module Enumerable(T) + def map_parallel(&block : T -> U) forall U + wait = Channel(U).new + num_fibers = 0 + self + .tap { |x| num_fibers = x.size } + .each do |x| + spawn do + wait.send(block.call(x)) + end + end + Array.new(num_fibers, nil) + .map { |x| wait.receive } + end +end -- 2.45.2