concurrently 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -0
  3. data/.rspec +4 -0
  4. data/.travis.yml +16 -0
  5. data/.yardopts +7 -0
  6. data/Gemfile +17 -0
  7. data/LICENSE +176 -0
  8. data/README.md +129 -0
  9. data/RELEASE_NOTES.md +49 -0
  10. data/Rakefile +28 -0
  11. data/concurrently.gemspec +33 -0
  12. data/ext/Ruby/thread.rb +28 -0
  13. data/ext/all/array.rb +24 -0
  14. data/ext/mruby/array.rb +19 -0
  15. data/ext/mruby/fiber.rb +5 -0
  16. data/ext/mruby/io.rb +54 -0
  17. data/guides/Installation.md +46 -0
  18. data/guides/Overview.md +335 -0
  19. data/guides/Performance.md +140 -0
  20. data/guides/Troubleshooting.md +262 -0
  21. data/lib/Ruby/concurrently.rb +12 -0
  22. data/lib/Ruby/concurrently/error.rb +4 -0
  23. data/lib/Ruby/concurrently/event_loop.rb +24 -0
  24. data/lib/Ruby/concurrently/event_loop/io_selector.rb +38 -0
  25. data/lib/all/concurrently/error.rb +10 -0
  26. data/lib/all/concurrently/evaluation.rb +109 -0
  27. data/lib/all/concurrently/evaluation/error.rb +18 -0
  28. data/lib/all/concurrently/event_loop.rb +101 -0
  29. data/lib/all/concurrently/event_loop/fiber.rb +37 -0
  30. data/lib/all/concurrently/event_loop/io_selector.rb +42 -0
  31. data/lib/all/concurrently/event_loop/proc_fiber_pool.rb +18 -0
  32. data/lib/all/concurrently/event_loop/run_queue.rb +111 -0
  33. data/lib/all/concurrently/proc.rb +233 -0
  34. data/lib/all/concurrently/proc/evaluation.rb +246 -0
  35. data/lib/all/concurrently/proc/fiber.rb +67 -0
  36. data/lib/all/concurrently/version.rb +8 -0
  37. data/lib/all/io.rb +248 -0
  38. data/lib/all/kernel.rb +201 -0
  39. data/lib/mruby/concurrently/proc.rb +21 -0
  40. data/lib/mruby/kernel.rb +15 -0
  41. data/mrbgem.rake +42 -0
  42. data/perf/_shared/stage.rb +33 -0
  43. data/perf/concurrent_proc_call.rb +13 -0
  44. data/perf/concurrent_proc_call_and_forget.rb +15 -0
  45. data/perf/concurrent_proc_call_detached.rb +15 -0
  46. data/perf/concurrent_proc_call_nonblock.rb +13 -0
  47. data/perf/concurrent_proc_calls.rb +49 -0
  48. data/perf/concurrent_proc_calls_awaiting.rb +48 -0
  49. metadata +144 -0
@@ -0,0 +1,21 @@
1
+ module Concurrently
2
+ # @api mruby_patches
3
+ # @since 1.0.0
4
+ #
5
+ # mruby's Proc does not support instance variables. So, whe have to make
6
+ # it a normal class that does not inherit from Proc :(
7
+ class Proc
8
+ def initialize(evaluation_class = Evaluation, &proc)
9
+ @evaluation_class = evaluation_class
10
+ @proc = proc
11
+ end
12
+
13
+ def arity
14
+ @proc.arity
15
+ end
16
+
17
+ def __proc_call__(*args)
18
+ @proc.call *args
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,15 @@
1
+ # @api mruby_patches
2
+ # @since 1.0.0
3
+ module Kernel
4
+ # Reimplements Kernel#concurrently. mruby does not support Proc.new without
5
+ # a block.
6
+ private def concurrently(*args, &block)
7
+ Concurrently::Proc.new(&block).call_and_forget *args
8
+ end
9
+
10
+ # Reimplements Kernel#concurrent_proc. mruby does not support Proc.new without
11
+ # a block.
12
+ private def concurrent_proc(evaluation_class = Concurrently::Proc::Evaluation, &block)
13
+ Concurrently::Proc.new(evaluation_class, &block)
14
+ end
15
+ end
data/mrbgem.rake ADDED
@@ -0,0 +1,42 @@
1
+ require_relative 'lib/all/concurrently/version'
2
+
3
+ MRuby::Gem::Specification.new('mruby-concurrently') do |spec|
4
+ spec.version = Concurrently::VERSION
5
+ spec.summary = %q{A concurrency framework based on fibers}
6
+ spec.description = <<-DESC
7
+ Concurrently is a concurrency framework for Ruby and mruby. With it, concurrent
8
+ code can be written sequentially similar to async/await.
9
+
10
+ The concurrency primitive of Concurrently is the concurrent proc. It is very
11
+ similar to a regular proc. Calling a concurrent proc creates a concurrent
12
+ evaluation which is kind of a lightweight thread: It can wait for stuff without
13
+ blocking other concurrent evaluations.
14
+
15
+ Under the hood, concurrent procs are evaluated inside fibers. They can wait for
16
+ readiness of I/O or a period of time (or the result of other concurrent
17
+ evaluations).
18
+ DESC
19
+
20
+ spec.homepage = "https://github.com/christopheraue/m-ruby-concurrently"
21
+ spec.license = 'Apache-2.0'
22
+ spec.authors = ['Christopher Aue']
23
+
24
+ # patch build process so we can set source files with spec.rbfiles
25
+ @generate_functions = true
26
+ @objs << objfile("#{build_dir}/gem_init")
27
+
28
+ spec.rbfiles =
29
+ Dir["#{spec.dir}/ext/all/**/*.rb"].sort +
30
+ Dir["#{spec.dir}/ext/mruby/**/*.rb"].sort +
31
+ Dir["#{spec.dir}/lib/all/**/*.rb"].sort +
32
+ Dir["#{spec.dir}/lib/mruby/**/*.rb"].sort
33
+ spec.test_rbfiles = Dir["#{spec.dir}/test/mruby/*.rb"]
34
+
35
+ spec.add_dependency 'mruby-array-ext'
36
+ spec.add_dependency 'mruby-numeric-ext'
37
+ spec.add_dependency 'mruby-enumerator'
38
+ spec.add_dependency 'mruby-fiber'
39
+ spec.add_dependency 'mruby-time'
40
+ spec.add_dependency 'mruby-io'
41
+ spec.add_dependency 'mruby-callbacks_attachable', '~> 2.2', github: 'christopheraue/m-ruby-callbacks_attachable'
42
+ end
@@ -0,0 +1,33 @@
1
+ require 'bundler'
2
+
3
+ Bundler.require :default
4
+ Bundler.require :perf
5
+
6
+ class Stage
7
+ def measure(seconds: 1) # &test
8
+ GC.start
9
+ GC.disable
10
+ profile = RubyProf::Profile.new(merge_fibers: true).tap(&:start) if ARGV[0] == 'profile'
11
+
12
+ event_loop = Concurrently::EventLoop.current
13
+ event_loop.reinitialize!
14
+ iterations = 0
15
+ start_time = event_loop.lifetime
16
+ end_time = start_time + seconds
17
+ while event_loop.lifetime < end_time
18
+ yield
19
+ iterations += 1
20
+ end
21
+ stop_time = event_loop.lifetime
22
+
23
+ if ARGV[0] == 'profile'
24
+ printer = ARGV[1].dup || 'flat'
25
+ printer[0] = printer[0].capitalize
26
+ RubyProf.const_get("#{printer}Printer").new(profile.stop).print(STDOUT, sort_method: :self_time)
27
+ end
28
+ GC.enable
29
+
30
+ { iterations: iterations, time: (stop_time-start_time) }
31
+ end
32
+ end
33
+
@@ -0,0 +1,13 @@
1
+ #!/bin/env ruby
2
+
3
+ require_relative "_shared/stage"
4
+
5
+ stage = Stage.new
6
+
7
+ conproc = concurrent_proc{}
8
+
9
+ result = stage.measure(seconds: 1) do
10
+ conproc.call
11
+ end
12
+
13
+ puts "#{result[:iterations]} executions in #{result[:time].round 4} seconds"
@@ -0,0 +1,15 @@
1
+ #!/bin/env ruby
2
+
3
+ require_relative "_shared/stage"
4
+
5
+ stage = Stage.new
6
+
7
+ evaluation = Concurrently::Evaluation.current
8
+ conproc = concurrent_proc{ evaluation.resume! }
9
+
10
+ result = stage.measure(seconds: 1) do
11
+ conproc.call_and_forget
12
+ await_resume!
13
+ end
14
+
15
+ puts "#{result[:iterations]} executions in #{result[:time].round 4} seconds"
@@ -0,0 +1,15 @@
1
+ #!/bin/env ruby
2
+
3
+ require_relative "_shared/stage"
4
+
5
+ stage = Stage.new
6
+
7
+ evaluation = Concurrently::Evaluation.current
8
+ conproc = concurrent_proc{ evaluation.resume! }
9
+
10
+ result = stage.measure(seconds: 1) do
11
+ conproc.call_detached
12
+ await_resume!
13
+ end
14
+
15
+ puts "#{result[:iterations]} executions in #{result[:time].round 4} seconds"
@@ -0,0 +1,13 @@
1
+ #!/bin/env ruby
2
+
3
+ require_relative "_shared/stage"
4
+
5
+ stage = Stage.new
6
+
7
+ conproc = concurrent_proc{}
8
+
9
+ result = stage.measure(seconds: 1) do
10
+ conproc.call_nonblock
11
+ end
12
+
13
+ puts "#{result[:iterations]} executions in #{result[:time].round 4} seconds"
@@ -0,0 +1,49 @@
1
+ #!/bin/env ruby
2
+
3
+ require_relative "_shared/stage"
4
+
5
+ stage = Stage.new
6
+ format = " %-25s %7d executions in %2.4f seconds"
7
+
8
+ puts <<-DOC
9
+ Benchmarked Code
10
+ ----------------
11
+ proc = proc{}
12
+ conproc = concurrent_proc{}
13
+
14
+ while elapsed_seconds < 1
15
+ # CODE #
16
+ end
17
+
18
+ Results
19
+ -------
20
+ # CODE #
21
+ DOC
22
+
23
+ proc = proc{}
24
+ conproc = concurrent_proc{}
25
+
26
+ result = stage.measure(seconds: 1) do
27
+ proc.call
28
+ end
29
+ puts sprintf(format, "proc.call:", result[:iterations], result[:time])
30
+
31
+ result = stage.measure(seconds: 1) do
32
+ conproc.call
33
+ end
34
+ puts sprintf(format, "conproc.call:", result[:iterations], result[:time])
35
+
36
+ result = stage.measure(seconds: 1) do
37
+ conproc.call_nonblock
38
+ end
39
+ puts sprintf(format, "conproc.call_nonblock:", result[:iterations], result[:time])
40
+
41
+ result = stage.measure(seconds: 1) do
42
+ conproc.call_detached
43
+ end
44
+ puts sprintf(format, "conproc.call_detached:", result[:iterations], result[:time])
45
+
46
+ result = stage.measure(seconds: 1) do
47
+ conproc.call_and_forget
48
+ end
49
+ puts sprintf(format, "conproc.call_and_forget:", result[:iterations], result[:time])
@@ -0,0 +1,48 @@
1
+ #!/bin/env ruby
2
+
3
+ require_relative "_shared/stage"
4
+
5
+ stage = Stage.new
6
+ format = " %-25s %7d executions in %2.4f seconds"
7
+ factor = ARGV.fetch(0, 1).to_i
8
+
9
+ puts <<-DOC
10
+ Benchmarked Code
11
+ ----------------
12
+ conproc = concurrent_proc{ wait 0 }
13
+
14
+ while elapsed_seconds < 1
15
+ #{factor}.times{ # CODE # }
16
+ wait 0 # to enter the event loop
17
+ end
18
+
19
+ Results
20
+ -------
21
+ # CODE #
22
+ DOC
23
+
24
+ conproc = concurrent_proc{ wait 0 }
25
+
26
+ result = stage.measure(seconds: 1) do
27
+ factor.times{ conproc.call }
28
+ # no need to enter the event loop manually. It already happens in #call
29
+ end
30
+ puts sprintf(format, "conproc.call:", factor*result[:iterations], result[:time])
31
+
32
+ result = stage.measure(seconds: 1) do
33
+ factor.times{ conproc.call_nonblock }
34
+ wait 0
35
+ end
36
+ puts sprintf(format, "conproc.call_nonblock:", factor*result[:iterations], result[:time])
37
+
38
+ result = stage.measure(seconds: 1) do
39
+ factor.times{ conproc.call_detached }
40
+ wait 0
41
+ end
42
+ puts sprintf(format, "conproc.call_detached:", factor*result[:iterations], result[:time])
43
+
44
+ result = stage.measure(seconds: 1) do
45
+ factor.times{ conproc.call_and_forget }
46
+ wait 0
47
+ end
48
+ puts sprintf(format, "conproc.call_and_forget:", factor*result[:iterations], result[:time])
metadata ADDED
@@ -0,0 +1,144 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: concurrently
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Christopher Aue
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-06-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: nio4r
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: hitimes
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.2'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: callbacks_attachable
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.2'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.2'
55
+ description: |
56
+ Concurrently is a concurrency framework for Ruby and mruby. With it, concurrent
57
+ code can be written sequentially similar to async/await.
58
+
59
+ The concurrency primitive of Concurrently is the concurrent proc. It is very
60
+ similar to a regular proc. Calling a concurrent proc creates a concurrent
61
+ evaluation which is kind of a lightweight thread: It can wait for stuff without
62
+ blocking other concurrent evaluations.
63
+
64
+ Under the hood, concurrent procs are evaluated inside fibers. They can wait for
65
+ readiness of I/O or a period of time (or the result of other concurrent
66
+ evaluations).
67
+ email:
68
+ - rubygems@christopheraue.net
69
+ executables: []
70
+ extensions: []
71
+ extra_rdoc_files: []
72
+ files:
73
+ - ".gitignore"
74
+ - ".rspec"
75
+ - ".travis.yml"
76
+ - ".yardopts"
77
+ - Gemfile
78
+ - LICENSE
79
+ - README.md
80
+ - RELEASE_NOTES.md
81
+ - Rakefile
82
+ - concurrently.gemspec
83
+ - ext/Ruby/thread.rb
84
+ - ext/all/array.rb
85
+ - ext/mruby/array.rb
86
+ - ext/mruby/fiber.rb
87
+ - ext/mruby/io.rb
88
+ - guides/Installation.md
89
+ - guides/Overview.md
90
+ - guides/Performance.md
91
+ - guides/Troubleshooting.md
92
+ - lib/Ruby/concurrently.rb
93
+ - lib/Ruby/concurrently/error.rb
94
+ - lib/Ruby/concurrently/event_loop.rb
95
+ - lib/Ruby/concurrently/event_loop/io_selector.rb
96
+ - lib/all/concurrently/error.rb
97
+ - lib/all/concurrently/evaluation.rb
98
+ - lib/all/concurrently/evaluation/error.rb
99
+ - lib/all/concurrently/event_loop.rb
100
+ - lib/all/concurrently/event_loop/fiber.rb
101
+ - lib/all/concurrently/event_loop/io_selector.rb
102
+ - lib/all/concurrently/event_loop/proc_fiber_pool.rb
103
+ - lib/all/concurrently/event_loop/run_queue.rb
104
+ - lib/all/concurrently/proc.rb
105
+ - lib/all/concurrently/proc/evaluation.rb
106
+ - lib/all/concurrently/proc/fiber.rb
107
+ - lib/all/concurrently/version.rb
108
+ - lib/all/io.rb
109
+ - lib/all/kernel.rb
110
+ - lib/mruby/concurrently/proc.rb
111
+ - lib/mruby/kernel.rb
112
+ - mrbgem.rake
113
+ - perf/_shared/stage.rb
114
+ - perf/concurrent_proc_call.rb
115
+ - perf/concurrent_proc_call_and_forget.rb
116
+ - perf/concurrent_proc_call_detached.rb
117
+ - perf/concurrent_proc_call_nonblock.rb
118
+ - perf/concurrent_proc_calls.rb
119
+ - perf/concurrent_proc_calls_awaiting.rb
120
+ homepage: https://github.com/christopheraue/m-ruby-concurrently
121
+ licenses:
122
+ - Apache-2.0
123
+ metadata: {}
124
+ post_install_message:
125
+ rdoc_options: []
126
+ require_paths:
127
+ - lib/Ruby
128
+ required_ruby_version: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: 2.2.7
133
+ required_rubygems_version: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ requirements: []
139
+ rubyforge_project:
140
+ rubygems_version: 2.6.11
141
+ signing_key:
142
+ specification_version: 4
143
+ summary: A concurrency framework based on fibers
144
+ test_files: []