branch 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +7 -0
- data/LICENSE.md +22 -0
- data/README.md +126 -0
- data/lib/branch.rb +33 -0
- metadata +50 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7c72ad76f5d6090801c0cd8b5f6a5c6652390034
|
4
|
+
data.tar.gz: 58d91717c99e5bc49be2c78eb3928cede01b7687
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ac7ed88f7af8615dd991413660823fdd3144b4aa310419583563b58e5194f6df7115f8a980dd62447f22f71e1d8f19e23c01e0845cd7b6e2437f8fdb24067aaf
|
7
|
+
data.tar.gz: db6744d098f641eed0d2d8cacad99b8d90799d532bd4f5a4bc9e20b85a833c90b014f308ce6c0cbffabb19f517a74eda532d35d5958cda1fa9a0f78d8937b2a3
|
data/CHANGELOG.md
ADDED
data/LICENSE.md
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
=====================
|
3
|
+
|
4
|
+
Copyright (c) 2014 Andrey 'lolmaus' Mikhaylov
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
8
|
+
in the Software without restriction, including without limitation the rights
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
11
|
+
furnished to do so, subject to the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
14
|
+
copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
22
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
Branch
|
2
|
+
======
|
3
|
+
|
4
|
+
**Run blocks asynchronously with little effort. A Ruby equivalent for JS `setTimeout`.**
|
5
|
+
|
6
|
+
This tiny lib was written to slightly reduce the amount of scaffolding required to do threads in Ruby. It is aimed at simpler use cases, for more complicated scenarios using vanilla thread syntax is recommended.
|
7
|
+
|
8
|
+
I hope Branch can save some frustration for people who discover that implementing a straightforward JS `setTimeout(function() { ... }, 0)` with Ruby is much more complicated and less intuitive. On the other hand, Branch is not an escape from getting to know how threads work.
|
9
|
+
|
10
|
+
|
11
|
+
How it works
|
12
|
+
------------
|
13
|
+
|
14
|
+
1. First of all, wrap your code with the `Branch.new { ... }` wrapper.
|
15
|
+
2. Within that wrapper, the `branch { ... }` method is available. It starts the passed block in a new asynchronous thread.
|
16
|
+
3. The end of the `Branch.new { ... }` wrapper will wait for all the threads to finish. In other words, the end of wrapper synchonizes your code. If you start another `Branch.new { ... }` afterwards, it will start sequentially after the previous branch is complete.
|
17
|
+
4. To start a thread with a delay, use `branch(2) { ... }`. This example will be executed after two seconds, without blocking the main thread.
|
18
|
+
5. If you need to synchronize a certain operation in order to prevent a race condition (JS coders beware!), you can use a mutex like this:
|
19
|
+
|
20
|
+
```rb
|
21
|
+
branch do |mutexes|
|
22
|
+
mutexes[:meaningful_mutex_name].synchronize { ... }
|
23
|
+
end
|
24
|
+
```
|
25
|
+
|
26
|
+
6. You don't need to instantiate mutexes manually. To reuse a mutex in another thread, simply access the `mutexes` hash with the same key. You can use anything for keys, e. g. integers, but a meaningful symbol is recommended.
|
27
|
+
7. Within a `branch`, you can use as many mutexes as you need.
|
28
|
+
|
29
|
+
|
30
|
+
|
31
|
+
Example usage
|
32
|
+
-------------
|
33
|
+
|
34
|
+
Please look into these pieces of code to see how Branch usage compares to vanilla syntax
|
35
|
+
|
36
|
+
|
37
|
+
### Simple example
|
38
|
+
|
39
|
+
#### Vanilla threads
|
40
|
+
|
41
|
+
Requires a fair amount of scaffolding:
|
42
|
+
|
43
|
+
* A thread array is to be defined manually.
|
44
|
+
* Each thread should be added to that array.
|
45
|
+
* Threads should be joined so that the main script doesn't exit before all threads finish.
|
46
|
+
|
47
|
+
```rb
|
48
|
+
threads = []
|
49
|
+
puts "Starting threads"
|
50
|
+
threads << Thread.new { sleep 5; puts "Thread 1 finished." }
|
51
|
+
threads << Thread.new { sleep 2; puts "Thread 2 finished." }
|
52
|
+
threads << Thread.new { sleep 1; puts "Thread 3 finished." }
|
53
|
+
puts "All threads started."
|
54
|
+
threads.each { |t| t.join }
|
55
|
+
puts "All threads complete."
|
56
|
+
```
|
57
|
+
|
58
|
+
|
59
|
+
#### Branch equivalent
|
60
|
+
|
61
|
+
All the scaffolding you need is you need is a `Branch.new { }` wrapper.
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
Branch.new do
|
65
|
+
puts "Starting threads"
|
66
|
+
branch { sleep 5; puts "Thread 1 finished." }
|
67
|
+
branch { sleep 2; puts "Thread 2 finished." }
|
68
|
+
branch { sleep 1; puts "Thread 3 finished." }
|
69
|
+
puts "All threads started."
|
70
|
+
end
|
71
|
+
puts "All threads complete."
|
72
|
+
```
|
73
|
+
|
74
|
+
|
75
|
+
|
76
|
+
|
77
|
+
### Thread synchronization with multiple mutexes
|
78
|
+
|
79
|
+
All mutexes have to be instantiated manually.
|
80
|
+
|
81
|
+
#### Vanilla threads
|
82
|
+
|
83
|
+
```rb
|
84
|
+
threads = []
|
85
|
+
|
86
|
+
mutex_array_access = Mutex.new
|
87
|
+
mutex_database_transaction = Mutex.new
|
88
|
+
mutex_coffee_brewing = Mutex.new
|
89
|
+
|
90
|
+
10.times do
|
91
|
+
threads << Thread.new do
|
92
|
+
|
93
|
+
# Imitating a time-consuming operation
|
94
|
+
sleep rand(1..5)
|
95
|
+
|
96
|
+
mutex_array_access .synchronize { shared_array << 'foo' if shared_array.length < 5 }
|
97
|
+
mutex_database_transaction.synchronize { DB::send('foo', 888) { |foo| foo.bar }}
|
98
|
+
mutex_coffee_brewing .synchronize { coffee_machine.clean.fill('water').make_coffee }
|
99
|
+
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
threads.each { |t| t.join }
|
104
|
+
```
|
105
|
+
|
106
|
+
|
107
|
+
#### Branch equivalent
|
108
|
+
|
109
|
+
Mutexes are instantiated automatically when they're first used and will persist throughuout the `Branch.new{ }` wrapper.
|
110
|
+
|
111
|
+
```ruby
|
112
|
+
Branch.new do
|
113
|
+
10.times do
|
114
|
+
branch do |mutexes|
|
115
|
+
|
116
|
+
# Imitating a time-consuming operation
|
117
|
+
sleep rand(1..5)
|
118
|
+
|
119
|
+
mutexes[:array_access] .synchronize { shared_array << 'foo' if shared_array.length < 5 }
|
120
|
+
mutexes[:database_transaction].synchronize { DB::send('foo', 888) { |foo| foo.bar }}
|
121
|
+
mutexes[:coffee_brewing] .synchronize { coffee_machine.clean.fill('water').make_coffee }
|
122
|
+
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
```
|
data/lib/branch.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
class Branch
|
2
|
+
|
3
|
+
VERSION = "0.1.0"
|
4
|
+
DATE = "2014-07-31"
|
5
|
+
|
6
|
+
def initialize(&block)
|
7
|
+
@threads = []
|
8
|
+
@mutexes = Hash.new { |hash, key| hash[key] = Mutex.new }
|
9
|
+
|
10
|
+
# Executing the passed block within the context
|
11
|
+
# of this class' instance.
|
12
|
+
instance_eval &block if block_given?
|
13
|
+
|
14
|
+
# Waiting for all threads to finish
|
15
|
+
@threads.each { |thr| thr.join }
|
16
|
+
end
|
17
|
+
|
18
|
+
# This method will be available within a block
|
19
|
+
# passed to `Branch.new`.
|
20
|
+
def branch(delay = false, &block)
|
21
|
+
|
22
|
+
# Starting a new thread
|
23
|
+
@threads << Thread.new do
|
24
|
+
|
25
|
+
# Implementing the timeout functionality
|
26
|
+
sleep delay if delay.is_a? Numeric
|
27
|
+
|
28
|
+
# Executing the block passed to `branch`,
|
29
|
+
# providing mutexes into the block.
|
30
|
+
block.call @mutexes
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
metadata
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: branch
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- lolmaus (Andrey Mikhaylov)
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-07-31 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Run blocks asynchronously with little effort, a Ruby equivalent for JS
|
14
|
+
setTimeout
|
15
|
+
email:
|
16
|
+
- lolmaus@gmail.com
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- CHANGELOG.md
|
22
|
+
- LICENSE.md
|
23
|
+
- README.md
|
24
|
+
- lib/branch.rb
|
25
|
+
homepage: https://github.com/lolmaus/branch
|
26
|
+
licenses:
|
27
|
+
- MIT
|
28
|
+
metadata: {}
|
29
|
+
post_install_message:
|
30
|
+
rdoc_options: []
|
31
|
+
require_paths:
|
32
|
+
- lib
|
33
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
34
|
+
requirements:
|
35
|
+
- - ">="
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 1.3.6
|
43
|
+
requirements: []
|
44
|
+
rubyforge_project:
|
45
|
+
rubygems_version: 2.2.2
|
46
|
+
signing_key:
|
47
|
+
specification_version: 4
|
48
|
+
summary: This gem tries to reduce the amount of scaffolding required to be built manually
|
49
|
+
in order to fire a couple of threads.
|
50
|
+
test_files: []
|