fibril 0.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.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +38 -0
- data/Rakefile +10 -0
- data/bin/fibril +19 -0
- data/bin/setup +7 -0
- data/examples/example_1.rb +71 -0
- data/examples/example_2.rb +80 -0
- data/examples/example_3.rb +82 -0
- data/examples/example_async.rb +27 -0
- data/examples/example_guard.rb +15 -0
- data/examples/example_loop.rb +13 -0
- data/examples/example_promise.rb +23 -0
- data/fibril.gemspec +31 -0
- data/fibril.todo +39 -0
- data/lib/fibril/loop.rb +11 -0
- data/lib/fibril/version.rb +3 -0
- data/lib/fibril.rb +241 -0
- metadata +154 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: cf7d153b66e754a9c54176ad4aed2f7b6e5b0055
|
4
|
+
data.tar.gz: 57d3036405946c6c82bfce1cea816c119d5f71fd
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 75bb606b9261c086109e971235f29fc624371db80f428e653b9918766d2346f674b4ce03e1a16ebb76239c8e22377a37b9a4b5ab3ef6e2b433eb5717f06b6479
|
7
|
+
data.tar.gz: d104f2d54afe2eeef3da5caae50b4d782576b7bb396caca58fd0986213c29eb0d9c87a45ce5844f3630b43dc5d67037546ba6d2ab5d1d9546af3ad5d1da47e96
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Wouter Coppieters
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# Fibril
|
2
|
+
|
3
|
+
|
4
|
+
## Installation
|
5
|
+
|
6
|
+
Add this line to your application's Gemfile:
|
7
|
+
|
8
|
+
```ruby
|
9
|
+
gem 'fibril'
|
10
|
+
```
|
11
|
+
|
12
|
+
And then execute:
|
13
|
+
|
14
|
+
$ bundle
|
15
|
+
|
16
|
+
Or install it yourself as:
|
17
|
+
|
18
|
+
$ gem install fibril
|
19
|
+
|
20
|
+
## Usage
|
21
|
+
|
22
|
+
TODO: Write usage instructions here
|
23
|
+
|
24
|
+
## Development
|
25
|
+
|
26
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
27
|
+
|
28
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
29
|
+
|
30
|
+
## Contributing
|
31
|
+
|
32
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/fibril.
|
33
|
+
|
34
|
+
|
35
|
+
## License
|
36
|
+
|
37
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
38
|
+
|
data/Rakefile
ADDED
data/bin/fibril
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "fibril"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
require "pry"
|
11
|
+
if ARGV[0]
|
12
|
+
require_relative "../#{ARGV[0]}"
|
13
|
+
else
|
14
|
+
Pry.start
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
# require "irb"
|
19
|
+
# IRB.start
|
data/bin/setup
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
require_relative '../lib/fibril'
|
2
|
+
|
3
|
+
require 'benchmark'
|
4
|
+
|
5
|
+
|
6
|
+
def get_5
|
7
|
+
5.tap{ async.sleep 0.5 }
|
8
|
+
end
|
9
|
+
|
10
|
+
def get_res
|
11
|
+
starts = Time.now
|
12
|
+
res = get_5
|
13
|
+
ends = Time.now
|
14
|
+
puts "Get res took #{ends - starts}"
|
15
|
+
res
|
16
|
+
end
|
17
|
+
Benchmark.bm do |bm|
|
18
|
+
# bm.report{
|
19
|
+
# Fibril do
|
20
|
+
# i = 0
|
21
|
+
# await fibril{ i = get_5 + 20 + i }.until{ i > 260 },
|
22
|
+
# fibril{ i = get_5 + 100 + i }.loop(2) do
|
23
|
+
# puts "Final i is #{i}"
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
# }
|
27
|
+
|
28
|
+
# puts "Done"
|
29
|
+
# sleep 2
|
30
|
+
bm.report{
|
31
|
+
|
32
|
+
Fibril do
|
33
|
+
i = 0
|
34
|
+
await(
|
35
|
+
fibril{ starts = Time.now; res = get_res;i = res + 20 + i; puts "Weave 1 took #{Time.now - starts}" }.until{ i > 260 },
|
36
|
+
fibril{ starts = Time.now; res = get_res;i = res + 100 + i; puts "Weave 2 took #{Time.now - starts}" }.loop(2)
|
37
|
+
) do
|
38
|
+
puts "Final i is #{i}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
# Fibril do
|
46
|
+
# await fibril{ puts 1; tick; puts 3 },
|
47
|
+
# fibril{ puts 2; tick; puts 4 } do
|
48
|
+
# puts "Finished"
|
49
|
+
# end
|
50
|
+
# end
|
51
|
+
# }
|
52
|
+
# end
|
53
|
+
|
54
|
+
|
55
|
+
|
56
|
+
# Thread.new do
|
57
|
+
# [
|
58
|
+
# Thread.new do
|
59
|
+
# puts "Big very very very very long message 1"
|
60
|
+
# puts "Big very very very very long message 2"
|
61
|
+
# puts "Big very very very very long message 5"
|
62
|
+
# puts "Big very very very very long message 6"
|
63
|
+
# end,
|
64
|
+
# Thread.new do
|
65
|
+
# puts "Big very very very very long message 3"
|
66
|
+
# puts "Big very very very very long message 4"
|
67
|
+
# puts "Big very very very very long message 7"
|
68
|
+
# puts "Big very very very very long message 8"
|
69
|
+
# end
|
70
|
+
# ].each(&:join)
|
71
|
+
# end.join
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require_relative 'fibril'
|
2
|
+
require "benchmark"
|
3
|
+
|
4
|
+
Benchmark.bm do |bm|
|
5
|
+
bm.report{
|
6
|
+
i = 0
|
7
|
+
100.times do
|
8
|
+
puts "A very long output statement : #{1}. Current thread: #{Thread.current}"
|
9
|
+
puts "A very long output statement : #{2}. Current thread: #{Thread.current}"
|
10
|
+
puts "A very long output statement : #{3}. Current thread: #{Thread.current}"
|
11
|
+
puts "A very long output statement : #{4}. Current thread: #{Thread.current}"
|
12
|
+
puts "A very long output statement : #{5}. Current thread: #{Thread.current}"
|
13
|
+
puts "A very long output statement : #{6}. Current thread: #{Thread.current}"
|
14
|
+
puts "A very long output statement : #{7}. Current thread: #{Thread.current}"
|
15
|
+
puts "A very long output statement : #{8}. Current thread: #{Thread.current}"
|
16
|
+
end
|
17
|
+
}
|
18
|
+
bm.report{
|
19
|
+
i = 0
|
20
|
+
|
21
|
+
100.times do
|
22
|
+
Fibril do
|
23
|
+
Fibril do
|
24
|
+
puts "A very long output statement : #{1}. Current thread: #{Thread.current}"
|
25
|
+
puts "A very long output statement : #{2}. Current thread: #{Thread.current}"
|
26
|
+
tick
|
27
|
+
puts "A very long output statement : #{3}. Current thread: #{Thread.current}"
|
28
|
+
puts "A very long output statement : #{4}. Current thread: #{Thread.current}"
|
29
|
+
end
|
30
|
+
|
31
|
+
Fibril do
|
32
|
+
puts "A very long output statement : #{5}. Current thread: #{Thread.current}"
|
33
|
+
puts "A very long output statement : #{6}. Current thread: #{Thread.current}"
|
34
|
+
tick
|
35
|
+
puts "A very long output statement : #{7}. Current thread: #{Thread.current}"
|
36
|
+
puts "A very long output statement : #{8}. Current thread: #{Thread.current}"
|
37
|
+
Fibril.stop
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
}
|
42
|
+
bm.report{
|
43
|
+
i = 0
|
44
|
+
100.times do
|
45
|
+
Thread.new do
|
46
|
+
[
|
47
|
+
Thread.new do
|
48
|
+
puts "A very long output statement : #{1}. Current thread: #{Thread.current}"
|
49
|
+
puts "A very long output statement : #{2}. Current thread: #{Thread.current}"
|
50
|
+
puts "A very long output statement : #{3}. Current thread: #{Thread.current}"
|
51
|
+
puts "A very long output statement : #{4}. Current thread: #{Thread.current}"
|
52
|
+
end,
|
53
|
+
Thread.new do
|
54
|
+
puts "A very long output statement : #{5}. Current thread: #{Thread.current}"
|
55
|
+
puts "A very long output statement : #{6}. Current thread: #{Thread.current}"
|
56
|
+
puts "A very long output statement : #{7}. Current thread: #{Thread.current}"
|
57
|
+
puts "A very long output statement : #{8}. Current thread: #{Thread.current}"
|
58
|
+
end
|
59
|
+
].each(&:join)
|
60
|
+
end.join
|
61
|
+
end
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
# Thread.new do
|
66
|
+
# [
|
67
|
+
# Thread.new do
|
68
|
+
# puts "Big very very very very long message 1"
|
69
|
+
# puts "Big very very very very long message 2"
|
70
|
+
# puts "Big very very very very long message 5"
|
71
|
+
# puts "Big very very very very long message 6"
|
72
|
+
# end,
|
73
|
+
# Thread.new do
|
74
|
+
# puts "Big very very very very long message 3"
|
75
|
+
# puts "Big very very very very long message 4"
|
76
|
+
# puts "Big very very very very long message 7"
|
77
|
+
# puts "Big very very very very long message 8"
|
78
|
+
# end
|
79
|
+
# ].each(&:join)
|
80
|
+
# end.join
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require_relative '../lib/fibril'
|
2
|
+
require "benchmark"
|
3
|
+
|
4
|
+
Benchmark.bm do |bm|
|
5
|
+
bm.report{
|
6
|
+
i = 0
|
7
|
+
1_000.times do
|
8
|
+
print "\rA very long output statement : #{1}. Current thread: #{Thread.current}"
|
9
|
+
print "\rA very long output statement : #{2}. Current thread: #{Thread.current}"
|
10
|
+
print "\rA very long output statement : #{3}. Current thread: #{Thread.current}"
|
11
|
+
print "\rA very long output statement : #{4}. Current thread: #{Thread.current}"
|
12
|
+
print "\rA very long output statement : #{5}. Current thread: #{Thread.current}"
|
13
|
+
print "\rA very long output statement : #{6}. Current thread: #{Thread.current}"
|
14
|
+
print "\rA very long output statement : #{7}. Current thread: #{Thread.current}"
|
15
|
+
print "\rA very long output statement : #{8}. Current thread: #{Thread.current}"
|
16
|
+
end
|
17
|
+
puts
|
18
|
+
}
|
19
|
+
bm.report{
|
20
|
+
i = 0
|
21
|
+
|
22
|
+
1_000.times do
|
23
|
+
Fibril do
|
24
|
+
Fibril do
|
25
|
+
print "\rA very long output statement : #{1}. Current thread: #{Thread.current}"
|
26
|
+
print "\rA very long output statement : #{2}. Current thread: #{Thread.current}"
|
27
|
+
tick
|
28
|
+
print "\rA very long output statement : #{3}. Current thread: #{Thread.current}"
|
29
|
+
print "\rA very long output statement : #{4}. Current thread: #{Thread.current}"
|
30
|
+
end
|
31
|
+
|
32
|
+
Fibril do
|
33
|
+
print "\rA very long output statement : #{5}. Current thread: #{Thread.current}"
|
34
|
+
print "\rA very long output statement : #{6}. Current thread: #{Thread.current}"
|
35
|
+
tick
|
36
|
+
print "\rA very long output statement : #{7}. Current thread: #{Thread.current}"
|
37
|
+
print "\rA very long output statement : #{8}. Current thread: #{Thread.current}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
puts
|
42
|
+
}
|
43
|
+
bm.report{
|
44
|
+
i = 0
|
45
|
+
1_000.times do
|
46
|
+
Thread.new do
|
47
|
+
[
|
48
|
+
Thread.new do
|
49
|
+
print "\rA very long output statement : #{1}. Current thread: #{Thread.current}"
|
50
|
+
print "\rA very long output statement : #{2}. Current thread: #{Thread.current}"
|
51
|
+
print "\rA very long output statement : #{3}. Current thread: #{Thread.current}"
|
52
|
+
print "\rA very long output statement : #{4}. Current thread: #{Thread.current}"
|
53
|
+
end,
|
54
|
+
Thread.new do
|
55
|
+
print "\rA very long output statement : #{5}. Current thread: #{Thread.current}"
|
56
|
+
print "\rA very long output statement : #{6}. Current thread: #{Thread.current}"
|
57
|
+
print "\rA very long output statement : #{7}. Current thread: #{Thread.current}"
|
58
|
+
print "\rA very long output statement : #{8}. Current thread: #{Thread.current}"
|
59
|
+
end
|
60
|
+
].each(&:join)
|
61
|
+
end.join
|
62
|
+
end
|
63
|
+
puts
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
# Thread.new do
|
68
|
+
# [
|
69
|
+
# Thread.new do
|
70
|
+
# print "\rBig very very very very long message 1"
|
71
|
+
# print "\rBig very very very very long message 2"
|
72
|
+
# print "\rBig very very very very long message 5"
|
73
|
+
# print "\rBig very very very very long message 6"
|
74
|
+
# end,
|
75
|
+
# Thread.new do
|
76
|
+
# print "\rBig very very very very long message 3"
|
77
|
+
# print "\rBig very very very very long message 4"
|
78
|
+
# print "\rBig very very very very long message 7"
|
79
|
+
# print "\rBig very very very very long message 8"
|
80
|
+
# end
|
81
|
+
# ].each(&:join)
|
82
|
+
# end.join
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require_relative "../lib/fibril/loop"
|
2
|
+
|
3
|
+
fibril{
|
4
|
+
[1,2,3].async.each do |i|
|
5
|
+
puts i
|
6
|
+
end
|
7
|
+
}
|
8
|
+
|
9
|
+
fibril{
|
10
|
+
[4,5,6].async.each do |i|
|
11
|
+
puts i
|
12
|
+
end
|
13
|
+
}
|
14
|
+
# Kernel.send :alias_method, :old_puts, :puts
|
15
|
+
# Fibril::async :puts
|
16
|
+
|
17
|
+
# puts 1
|
18
|
+
# puts 2
|
19
|
+
# puts 3
|
20
|
+
|
21
|
+
# puts 4
|
22
|
+
# puts 5
|
23
|
+
# puts 6
|
24
|
+
|
25
|
+
# sleep
|
26
|
+
|
27
|
+
# old_puts "Done!"
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require_relative "../lib/fibril/loop"
|
2
|
+
|
3
|
+
pending = promise{ sleep 1; 3 }
|
4
|
+
pending2 = promise{ sleep 0.1; 4 }
|
5
|
+
|
6
|
+
fibril{
|
7
|
+
puts "First"
|
8
|
+
puts async.await(pending)
|
9
|
+
puts "First"
|
10
|
+
}
|
11
|
+
|
12
|
+
fibril{
|
13
|
+
puts "Second"
|
14
|
+
result = async.await_all pending, pending2
|
15
|
+
puts "Second"
|
16
|
+
puts "Result is #{result}"
|
17
|
+
}
|
18
|
+
|
19
|
+
fibril{
|
20
|
+
puts "Third"
|
21
|
+
puts async.await(pending2)
|
22
|
+
puts "Third"
|
23
|
+
}
|
data/fibril.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'fibril/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "fibril"
|
8
|
+
spec.version = Fibril::VERSION
|
9
|
+
spec.authors = ["Wouter Coppieters"]
|
10
|
+
spec.email = ["wouter.coppieters@youdo.co.nz"]
|
11
|
+
|
12
|
+
spec.summary = "Fibril"
|
13
|
+
spec.description = "Fibril"
|
14
|
+
spec.homepage = "https://github.com/wouterken/Fibril"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
# Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
|
18
|
+
# delete this section to allow pushing this gem to any host.
|
19
|
+
|
20
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
21
|
+
spec.bindir = "exe"
|
22
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
23
|
+
spec.require_paths = ["lib"]
|
24
|
+
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.10"
|
26
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
27
|
+
spec.add_development_dependency "byebug", "~> 8.2.1"
|
28
|
+
spec.add_development_dependency "pry-byebug", "~> 3.3.0"
|
29
|
+
spec.add_development_dependency 'pry', '~> 0.10.2', '>= 0.10.0'
|
30
|
+
spec.add_development_dependency "minitest"
|
31
|
+
end
|
data/fibril.todo
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
✔ Guard becomes event driven - no polling @done (16-02-18 09:28)
|
2
|
+
✔ Fibrils return single count guards @done (16-02-18 09:28)
|
3
|
+
✔ Can await one or more guards @done (16-02-18 09:28)
|
4
|
+
✔ Use semaphore type object for synchronising multiple async calls @done (16-02-18 19:03)
|
5
|
+
✔ Use counter to determine if any work left to do, if not auto-stop @done (16-02-18 19:03)
|
6
|
+
✔ Create event loop import @done (16-02-18 21:15)
|
7
|
+
✔ Create continous and counting loop construct @done (16-02-18 21:15)
|
8
|
+
✔ Create async object @done (16-02-19 07:35)
|
9
|
+
✔ Create promises @done (16-02-19 07:49)
|
10
|
+
✔ Turn into gem @done (16-02-19 07:49)
|
11
|
+
|
12
|
+
☐ Add keywords syntax highlighting in Sublime
|
13
|
+
- promise, async, fibril, await, await_all
|
14
|
+
|
15
|
+
☐ Create smarter loop importer. Finds import statement and only evals everything past itself
|
16
|
+
|
17
|
+
☐ Write performance tests
|
18
|
+
☐ Use efficient ring buffer as queue and block when full
|
19
|
+
|
20
|
+
☐ Examples:
|
21
|
+
|
22
|
+
☐ Weave with tick
|
23
|
+
☐ Weave with async IO
|
24
|
+
☐ Weave external await
|
25
|
+
☐ Weave with internal await
|
26
|
+
☐ Promises
|
27
|
+
|
28
|
+
☐ Disk read + write
|
29
|
+
☐ Database queries using AR
|
30
|
+
☐ Network IO
|
31
|
+
☐ Asyncifying common functions
|
32
|
+
☐ Asyncifying class methods
|
33
|
+
☐ Asyncifying instance methods
|
34
|
+
☐ Asyncifying module methods
|
35
|
+
☐ Comparison to thread
|
36
|
+
☐ Comparison to event machine
|
37
|
+
|
38
|
+
☐ Rename to Weave
|
39
|
+
☐ Refactor
|
data/lib/fibril/loop.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require_relative '../fibril'
|
2
|
+
require 'pry'
|
3
|
+
|
4
|
+
call_stack = caller
|
5
|
+
lines = IO.read(call_stack[0][/.*?(?=\:)/,0]).split("\n")
|
6
|
+
|
7
|
+
if %r{require.*".*?fibril/loop"} =~ lines[0].gsub("'",?").gsub(/\s+/,' ').strip
|
8
|
+
$LOAD_PATH << '.'
|
9
|
+
fibril{ eval lines[1..-1].join("\n") }
|
10
|
+
exit(0)
|
11
|
+
end
|
data/lib/fibril.rb
ADDED
@@ -0,0 +1,241 @@
|
|
1
|
+
require "fibril/version"
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
|
5
|
+
class Fibril < Fiber
|
6
|
+
class << self
|
7
|
+
attr_accessor :running, :stopped, :queue, :task_count, :guards, :current, :id_seq
|
8
|
+
end
|
9
|
+
|
10
|
+
self.queue = []
|
11
|
+
self.guards = Hash.new{|h,k| }
|
12
|
+
self.id_seq = 0
|
13
|
+
|
14
|
+
attr_accessor :fiber, :guards, :block, :id
|
15
|
+
|
16
|
+
def self.log(msg)
|
17
|
+
# puts msg
|
18
|
+
end
|
19
|
+
|
20
|
+
def variables
|
21
|
+
@@variables ||= OpenStruct.new
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize(&blk)
|
25
|
+
self.id = Fibril.id_seq += 1
|
26
|
+
self.block = blk
|
27
|
+
self.guards = []
|
28
|
+
define_singleton_method :execute_fibril, self.block
|
29
|
+
super(&method(:execute))
|
30
|
+
Fibril.queue << self
|
31
|
+
end
|
32
|
+
|
33
|
+
def reset(guard)
|
34
|
+
copy = Fibril.new(&self.block)
|
35
|
+
copy.guards << guard
|
36
|
+
return copy
|
37
|
+
end
|
38
|
+
|
39
|
+
def execute
|
40
|
+
Fibril.task_count += 1
|
41
|
+
execute_fibril
|
42
|
+
self.guards.each(&:visit)
|
43
|
+
Fibril.task_count -= 1
|
44
|
+
Fibril.log "Ending #{id}"
|
45
|
+
end
|
46
|
+
|
47
|
+
def tick
|
48
|
+
Fibril.enqueue self
|
49
|
+
self.yield
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.enqueue(fibril)
|
53
|
+
Fibril.log "Enqueing fibril #{fibril.id}"
|
54
|
+
Fibril.queue << fibril
|
55
|
+
end
|
56
|
+
|
57
|
+
def yield
|
58
|
+
Fibril.log "Yielding #{id}"
|
59
|
+
Fiber.yield
|
60
|
+
end
|
61
|
+
|
62
|
+
def current
|
63
|
+
self
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.deplete_guard(guard)
|
67
|
+
return unless waiters = guards[guard.id]
|
68
|
+
switches = waiters[:switches]
|
69
|
+
switches[guard.id] = true
|
70
|
+
waiters[:block][] if switches.values.all?
|
71
|
+
end
|
72
|
+
|
73
|
+
def await(*guards, &block)
|
74
|
+
|
75
|
+
if guards.length == 1 && guards[0].kind_of?(Promise)
|
76
|
+
return await_promise(guards[0])
|
77
|
+
end
|
78
|
+
|
79
|
+
await_block = {
|
80
|
+
switches: Hash[guards.map{|guard| [guard.id, false]}],
|
81
|
+
block: block
|
82
|
+
}
|
83
|
+
guards.each do |guard|
|
84
|
+
Fibril.guards[guard.id] = await_block
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def promise(&blk)
|
89
|
+
return Promise.new(&blk)
|
90
|
+
end
|
91
|
+
|
92
|
+
def await_promise(promise)
|
93
|
+
promise.await
|
94
|
+
end
|
95
|
+
|
96
|
+
def await_all(*promises)
|
97
|
+
promises.map(&:await)
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.stop
|
101
|
+
Fibril do
|
102
|
+
Fibril.stopped = true
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def resume
|
107
|
+
Fibril.current = self
|
108
|
+
Fibril.log "Resuming #{id}"
|
109
|
+
super
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.start
|
113
|
+
self.task_count = 0
|
114
|
+
self.stopped = false
|
115
|
+
self.running = true
|
116
|
+
if queue.any?
|
117
|
+
queue.shift.resume
|
118
|
+
self.loop if queue.any? || Fibril.task_count > 0
|
119
|
+
end
|
120
|
+
self.running = false
|
121
|
+
end
|
122
|
+
|
123
|
+
def self.loop
|
124
|
+
Fibril.log "Starting loop inside #{Fibril.current}"
|
125
|
+
while ((Fibril.task_count > 0 || queue.any?) && !Fibril.stopped)
|
126
|
+
Fibril.queue.shift.resume if Fibril.queue.any?
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def Guard(i, fibril)
|
131
|
+
return Guard.new(i, fibril)
|
132
|
+
end
|
133
|
+
|
134
|
+
class AsyncProxy
|
135
|
+
attr_accessor :target
|
136
|
+
|
137
|
+
def initialize(target)
|
138
|
+
self.target = target
|
139
|
+
end
|
140
|
+
|
141
|
+
def method_missing(name, *args, &block)
|
142
|
+
waiting = Fibril.current
|
143
|
+
Thread.new do
|
144
|
+
target.send(name, *args, &block).tap{ Fibril.enqueue waiting }
|
145
|
+
end.tap{
|
146
|
+
Fibril.current.yield
|
147
|
+
}.value
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
|
152
|
+
class Guard
|
153
|
+
class << self
|
154
|
+
attr_accessor :guard_seq
|
155
|
+
end
|
156
|
+
|
157
|
+
attr_accessor :fibril, :id, :break_condition, :depleted
|
158
|
+
|
159
|
+
self.guard_seq = 0
|
160
|
+
|
161
|
+
def self.create(fibril, counter=1)
|
162
|
+
self.guard_seq += 1
|
163
|
+
guard = Fibril::Guard.new(self.guard_seq, counter, fibril)
|
164
|
+
fibril.guards << guard
|
165
|
+
return guard
|
166
|
+
end
|
167
|
+
|
168
|
+
def await
|
169
|
+
Fibril.current.tick while !self.depleted
|
170
|
+
end
|
171
|
+
|
172
|
+
def initialize(id, counter, fibril)
|
173
|
+
self.id = id
|
174
|
+
self.fibril = fibril
|
175
|
+
self.break_condition = 1
|
176
|
+
end
|
177
|
+
|
178
|
+
def visit
|
179
|
+
case self.break_condition
|
180
|
+
when Proc
|
181
|
+
if self.break_condition[]
|
182
|
+
self.depleted = true
|
183
|
+
Fibril.deplete_guard(self)
|
184
|
+
else
|
185
|
+
self.fibril = self.fibril.reset(self)
|
186
|
+
end
|
187
|
+
else
|
188
|
+
self.break_condition -= 1
|
189
|
+
if self.break_condition.zero?
|
190
|
+
self.depleted = true
|
191
|
+
Fibril.deplete_guard(self)
|
192
|
+
else
|
193
|
+
self.fibril = self.fibril.reset(self)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def loop(break_condition=-1, &blck)
|
199
|
+
self.break_condition = block_given? ? blck : break_condition
|
200
|
+
self
|
201
|
+
end
|
202
|
+
|
203
|
+
def while(&blk)
|
204
|
+
loop{ !blk[] }
|
205
|
+
end
|
206
|
+
|
207
|
+
def until(&blk)
|
208
|
+
loop{ blk[] }
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
class Promise
|
213
|
+
attr_accessor :promise_thread
|
214
|
+
def initialize(&blk)
|
215
|
+
self.promise_thread = Thread.new(&blk)
|
216
|
+
end
|
217
|
+
|
218
|
+
def await
|
219
|
+
self.promise_thread.join.value
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
end
|
224
|
+
|
225
|
+
class ::BasicObject
|
226
|
+
def async
|
227
|
+
@async_proxy ||= ::Fibril::AsyncProxy.new(self)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
|
232
|
+
def Fibril(&block)
|
233
|
+
fibril = Fibril.new(&block).tap do |t|
|
234
|
+
Fibril.start unless Fibril.running
|
235
|
+
end
|
236
|
+
guard = Fibril::Guard.create(fibril)
|
237
|
+
end
|
238
|
+
|
239
|
+
|
240
|
+
|
241
|
+
Kernel.send :alias_method, :fibril, :Fibril
|
metadata
ADDED
@@ -0,0 +1,154 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fibril
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Wouter Coppieters
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-02-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.10'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.10'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: byebug
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 8.2.1
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 8.2.1
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pry-byebug
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 3.3.0
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 3.3.0
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: pry
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.10.2
|
76
|
+
- - ">="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: 0.10.0
|
79
|
+
type: :development
|
80
|
+
prerelease: false
|
81
|
+
version_requirements: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - "~>"
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 0.10.2
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: 0.10.0
|
89
|
+
- !ruby/object:Gem::Dependency
|
90
|
+
name: minitest
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
type: :development
|
97
|
+
prerelease: false
|
98
|
+
version_requirements: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
description: Fibril
|
104
|
+
email:
|
105
|
+
- wouter.coppieters@youdo.co.nz
|
106
|
+
executables: []
|
107
|
+
extensions: []
|
108
|
+
extra_rdoc_files: []
|
109
|
+
files:
|
110
|
+
- ".gitignore"
|
111
|
+
- ".travis.yml"
|
112
|
+
- Gemfile
|
113
|
+
- LICENSE.txt
|
114
|
+
- README.md
|
115
|
+
- Rakefile
|
116
|
+
- bin/fibril
|
117
|
+
- bin/setup
|
118
|
+
- examples/example_1.rb
|
119
|
+
- examples/example_2.rb
|
120
|
+
- examples/example_3.rb
|
121
|
+
- examples/example_async.rb
|
122
|
+
- examples/example_guard.rb
|
123
|
+
- examples/example_loop.rb
|
124
|
+
- examples/example_promise.rb
|
125
|
+
- fibril.gemspec
|
126
|
+
- fibril.todo
|
127
|
+
- lib/fibril.rb
|
128
|
+
- lib/fibril/loop.rb
|
129
|
+
- lib/fibril/version.rb
|
130
|
+
homepage: https://github.com/wouterken/Fibril
|
131
|
+
licenses:
|
132
|
+
- MIT
|
133
|
+
metadata: {}
|
134
|
+
post_install_message:
|
135
|
+
rdoc_options: []
|
136
|
+
require_paths:
|
137
|
+
- lib
|
138
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
139
|
+
requirements:
|
140
|
+
- - ">="
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
version: '0'
|
143
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
144
|
+
requirements:
|
145
|
+
- - ">="
|
146
|
+
- !ruby/object:Gem::Version
|
147
|
+
version: '0'
|
148
|
+
requirements: []
|
149
|
+
rubyforge_project:
|
150
|
+
rubygems_version: 2.4.5
|
151
|
+
signing_key:
|
152
|
+
specification_version: 4
|
153
|
+
summary: Fibril
|
154
|
+
test_files: []
|