M spec/gmi_renderer_spec.cr => spec/gmi_renderer_spec.cr +1 -0
@@ 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))
A spec/map_parallel_spec.cr => spec/map_parallel_spec.cr +21 -0
@@ 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
M spec/spec_helper.cr => spec/spec_helper.cr +0 -1
@@ 1,2 1,1 @@
require "spec"
-require "../src/gmi_renderer.cr"
M src/main.cr => src/main.cr +10 -16
@@ 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 }
A src/map_parallel.cr => src/map_parallel.cr +15 -0
@@ 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