concurrent-ruby 0.1.0 → 0.1.1.pre.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 (51) hide show
  1. data/LICENSE +21 -21
  2. data/README.md +279 -224
  3. data/lib/concurrent.rb +27 -20
  4. data/lib/concurrent/agent.rb +106 -130
  5. data/lib/concurrent/cached_thread_pool.rb +130 -122
  6. data/lib/concurrent/defer.rb +67 -69
  7. data/lib/concurrent/drb_async_demux.rb +72 -0
  8. data/lib/concurrent/event.rb +60 -60
  9. data/lib/concurrent/event_machine_defer_proxy.rb +23 -23
  10. data/lib/concurrent/executor.rb +87 -0
  11. data/lib/concurrent/fixed_thread_pool.rb +89 -89
  12. data/lib/concurrent/functions.rb +120 -0
  13. data/lib/concurrent/future.rb +52 -42
  14. data/lib/concurrent/global_thread_pool.rb +3 -3
  15. data/lib/concurrent/goroutine.rb +29 -25
  16. data/lib/concurrent/obligation.rb +67 -121
  17. data/lib/concurrent/promise.rb +172 -194
  18. data/lib/concurrent/reactor.rb +162 -0
  19. data/lib/concurrent/smart_mutex.rb +66 -0
  20. data/lib/concurrent/tcp_sync_demux.rb +96 -0
  21. data/lib/concurrent/thread_pool.rb +65 -61
  22. data/lib/concurrent/utilities.rb +34 -0
  23. data/lib/concurrent/version.rb +3 -3
  24. data/lib/concurrent_ruby.rb +1 -1
  25. data/md/agent.md +123 -123
  26. data/md/defer.md +174 -174
  27. data/md/event.md +32 -32
  28. data/md/executor.md +176 -0
  29. data/md/future.md +83 -83
  30. data/md/goroutine.md +52 -52
  31. data/md/obligation.md +32 -32
  32. data/md/promise.md +225 -225
  33. data/md/thread_pool.md +197 -197
  34. data/spec/concurrent/agent_spec.rb +376 -405
  35. data/spec/concurrent/cached_thread_pool_spec.rb +112 -112
  36. data/spec/concurrent/defer_spec.rb +209 -199
  37. data/spec/concurrent/event_machine_defer_proxy_spec.rb +250 -246
  38. data/spec/concurrent/event_spec.rb +134 -134
  39. data/spec/concurrent/executor_spec.rb +146 -0
  40. data/spec/concurrent/fixed_thread_pool_spec.rb +84 -84
  41. data/spec/concurrent/functions_spec.rb +57 -0
  42. data/spec/concurrent/future_spec.rb +125 -115
  43. data/spec/concurrent/goroutine_spec.rb +67 -52
  44. data/spec/concurrent/obligation_shared.rb +121 -121
  45. data/spec/concurrent/promise_spec.rb +299 -310
  46. data/spec/concurrent/smart_mutex_spec.rb +234 -0
  47. data/spec/concurrent/thread_pool_shared.rb +209 -209
  48. data/spec/concurrent/utilities_spec.rb +74 -0
  49. data/spec/spec_helper.rb +21 -19
  50. metadata +38 -14
  51. checksums.yaml +0 -7
@@ -1,32 +1,32 @@
1
- # Event
2
-
3
- TBD...
4
-
5
- ## Copyright
6
-
7
- *Concurrent Ruby* is Copyright © 2013 [Jerry D'Antonio](https://twitter.com/jerrydantonio).
8
- It is free software and may be redistributed under the terms specified in the LICENSE file.
9
-
10
- ## License
11
-
12
- Released under the MIT license.
13
-
14
- http://www.opensource.org/licenses/mit-license.php
15
-
16
- > Permission is hereby granted, free of charge, to any person obtaining a copy
17
- > of this software and associated documentation files (the "Software"), to deal
18
- > in the Software without restriction, including without limitation the rights
19
- > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
20
- > copies of the Software, and to permit persons to whom the Software is
21
- > furnished to do so, subject to the following conditions:
22
- >
23
- > The above copyright notice and this permission notice shall be included in
24
- > all copies or substantial portions of the Software.
25
- >
26
- > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27
- > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28
- > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29
- > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30
- > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31
- > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
32
- > THE SOFTWARE.
1
+ # Event
2
+
3
+ TBD...
4
+
5
+ ## Copyright
6
+
7
+ *Concurrent Ruby* is Copyright © 2013 [Jerry D'Antonio](https://twitter.com/jerrydantonio).
8
+ It is free software and may be redistributed under the terms specified in the LICENSE file.
9
+
10
+ ## License
11
+
12
+ Released under the MIT license.
13
+
14
+ http://www.opensource.org/licenses/mit-license.php
15
+
16
+ > Permission is hereby granted, free of charge, to any person obtaining a copy
17
+ > of this software and associated documentation files (the "Software"), to deal
18
+ > in the Software without restriction, including without limitation the rights
19
+ > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
20
+ > copies of the Software, and to permit persons to whom the Software is
21
+ > furnished to do so, subject to the following conditions:
22
+ >
23
+ > The above copyright notice and this permission notice shall be included in
24
+ > all copies or substantial portions of the Software.
25
+ >
26
+ > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27
+ > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28
+ > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29
+ > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30
+ > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31
+ > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
32
+ > THE SOFTWARE.
@@ -0,0 +1,176 @@
1
+ # Being of Sound Mind
2
+
3
+ A very common currency pattern is to run a thread that performs a task at regular
4
+ intervals. The thread that peforms the task sleeps for the given interval then
5
+ waked up and performs the task. Later, rinse, repeat... This pattern causes two
6
+ problems. First, it is difficult to test the business logic of the task becuse the
7
+ task itself is tightly couple with the threading. Second, an exception in the task
8
+ can cause the entire thread to abend. In a long-running application where the task
9
+ thread is intended to run for days/weeks/years a crashed task thread can pose a real
10
+ problem. The `Executor` class alleviates both problems.
11
+
12
+ When an executor is launched it starts a thread for monitoring the execution interval.
13
+ The executor thread does not perform the task, however. Instead, the executor
14
+ launches the task on a separat thread. The advantage of this approach is that if
15
+ the task crashes it will only kill the task thread, not the executor thread. The
16
+ executor thread can then log the success or failure of the task. The executor
17
+ can even be configured with a timeout value allowing it to kill a task that runs
18
+ to long and then log the error.
19
+
20
+ One other advantage of the `Executor` class is that it forces the bsiness logic to
21
+ be completely decoupled from the threading logic. The business logic can be tested
22
+ separately then passed to the an executor for scheduling and running.
23
+
24
+ Unlike some of the others concurrency objects in the library, executors do not
25
+ run on the global. In my experience the types of tasks that will benefit from
26
+ the `Executor` class tend to also be long running. For this reason they get their
27
+ own thread every time the task is executed.
28
+
29
+ ## ExecutionContext
30
+
31
+ When an executor is run the return value is an `ExecutionContext` object. An
32
+ `ExecutionContext` object has several attribute readers (`#name`, `#execution_interval`,
33
+ and `#timeout_interval`). It also provides several `Thread` operations which can
34
+ be performed against the internal thread. These include `#status`, `#join`, and
35
+ `kill`.
36
+
37
+ ## Custom Logging
38
+
39
+ An executor will write a log message to standard out at the completion of every
40
+ task run. When the task is successful the log message is tagged at the `:info`
41
+ level. When the task times out the log message is tagged at the `warn` level.
42
+ When the task fails tocomplete (most likely because of exception) the log
43
+ message is tagged at the `error` level.
44
+
45
+ The default logging behavior can be overridden by passing a `proc` to the executor
46
+ on creation. The block will be passes three (3) arguments every time it is run:
47
+ executor `name`, log `level`, and the log `msg` (message). The `proc` can do
48
+ whatever it wanst with these arguments.
49
+
50
+ ## Examples
51
+
52
+ A basic example:
53
+
54
+ ```ruby
55
+ require 'concurrent'
56
+
57
+ ec = Concurrent::Executor.run('Foo'){ puts 'Boom!' }
58
+
59
+ ec.name #=> "Foo"
60
+ ec.execution_interval #=> 60 == Concurrent::Executor::EXECUTION_INTERVAL
61
+ ec.timeout_interval #=> 30 == Concurrent::Executor::TIMEOUT_INTERVAL
62
+ ec.status #=> "sleep"
63
+
64
+ # wait 60 seconds...
65
+ #=> 'Boom!'
66
+ #=> ' INFO (2013-08-02 23:20:15) Foo: execution completed successfully'
67
+
68
+ ec.kill #=> true
69
+ ```
70
+
71
+ Both the execution_interval and the timeout_interval can be configured:
72
+
73
+ ```ruby
74
+ ec = Concurrent::Executor.run('Foo', execution_interval: 5, timeout_interval: 5) do
75
+ puts 'Boom!'
76
+ end
77
+
78
+ ec.execution_interval #=> 5
79
+ ec.timeout_interval #=> 5
80
+ ```
81
+
82
+ A simple example with timeout and task exception:
83
+
84
+ ```ruby
85
+ ec = Concurrent::Executor.run('Foo', execution_interval: 1, timeout_interval: 1){ sleep(10) }
86
+
87
+ #=> WARN (2013-08-02 23:45:26) Foo: execution timed out after 1 seconds
88
+ #=> WARN (2013-08-02 23:45:28) Foo: execution timed out after 1 seconds
89
+ #=> WARN (2013-08-02 23:45:30) Foo: execution timed out after 1 seconds
90
+
91
+ ec = Concurrent::Executor.run('Foo', execution_interval: 1){ raise StandardError }
92
+
93
+ #=> ERROR (2013-08-02 23:47:31) Foo: execution failed with error 'StandardError'
94
+ #=> ERROR (2013-08-02 23:47:32) Foo: execution failed with error 'StandardError'
95
+ #=> ERROR (2013-08-02 23:47:33) Foo: execution failed with error 'StandardError'
96
+ ```
97
+
98
+ For custom logging, simply provide a `proc` when creating an executor:
99
+
100
+ ```ruby
101
+ file_logger = proc do |name, level, msg|
102
+ open('executor.log', 'a') do |f|
103
+ f << ("%5s (%s) %s: %s\n" % [level.upcase, Time.now.strftime("%F %T"), name, msg])
104
+ end
105
+ end
106
+
107
+ ec = Concurrent::Executor.run('Foo', execution_interval: 5, logger: file_logger) do
108
+ puts 'Boom!'
109
+ end
110
+
111
+ # the log file contains
112
+ # INFO (2013-08-02 23:30:19) Foo: execution completed successfully
113
+ # INFO (2013-08-02 23:30:24) Foo: execution completed successfully
114
+ # INFO (2013-08-02 23:30:29) Foo: execution completed successfully
115
+ # INFO (2013-08-02 23:30:34) Foo: execution completed successfully
116
+ # INFO (2013-08-02 23:30:39) Foo: execution completed successfully
117
+ # INFO (2013-08-02 23:30:44) Foo: execution completed successfully
118
+ ```
119
+
120
+ It is also possible to access the default stdout logger from within a logger `proc`:
121
+
122
+ ```ruby
123
+ file_logger = proc do |name, level, msg|
124
+ Concurrent::Executor::STDOUT_LOGGER.call(name, level, msg)
125
+ open('executor.log', 'a') do |f|
126
+ f << ("%5s (%s) %s: %s\n" % [level.upcase, Time.now.strftime("%F %T"), name, msg])
127
+ end
128
+ end
129
+
130
+ ec = Concurrent::Executor.run('Foo', execution_interval: 5, logger: file_logger) do
131
+ puts 'Boom!'
132
+ end
133
+
134
+ # wait...
135
+
136
+ #=> Boom!
137
+ #=> INFO (2013-08-02 23:40:49) Foo: execution completed successfully
138
+ #=> Boom!
139
+ #=> INFO (2013-08-02 23:40:54) Foo: execution completed successfully
140
+ #=> Boom!
141
+ #=> INFO (2013-08-02 23:40:59) Foo: execution completed successfully
142
+
143
+ # and the log file contains
144
+ # INFO (2013-08-02 23:39:52) Foo: execution completed successfully
145
+ # INFO (2013-08-02 23:39:57) Foo: execution completed successfully
146
+ # INFO (2013-08-02 23:40:49) Foo: execution completed successfully
147
+ ```
148
+
149
+ ## Copyright
150
+
151
+ *Concurrent Ruby* is Copyright &copy; 2013 [Jerry D'Antonio](https://twitter.com/jerrydantonio).
152
+ It is free software and may be redistributed under the terms specified in the LICENSE file.
153
+
154
+ ## License
155
+
156
+ Released under the MIT license.
157
+
158
+ http://www.opensource.org/licenses/mit-license.php
159
+
160
+ > Permission is hereby granted, free of charge, to any person obtaining a copy
161
+ > of this software and associated documentation files (the "Software"), to deal
162
+ > in the Software without restriction, including without limitation the rights
163
+ > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
164
+ > copies of the Software, and to permit persons to whom the Software is
165
+ > furnished to do so, subject to the following conditions:
166
+ >
167
+ > The above copyright notice and this permission notice shall be included in
168
+ > all copies or substantial portions of the Software.
169
+ >
170
+ > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
171
+ > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
172
+ > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
173
+ > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
174
+ > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
175
+ > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
176
+ > THE SOFTWARE.
@@ -1,83 +1,83 @@
1
- # We're Sending You Back to the Future!
2
-
3
- Futures are inspired by [Clojure's](http://clojure.org/) [future](http://clojuredocs.org/clojure_core/clojure.core/future) keyword.
4
- A future represents a promise to complete an action at some time in the future. The action is atomic and permanent.
5
- The idea behind a future is to send an action off for asynchronous operation, do other stuff, then return and
6
- retrieve the result of the async operation at a later time. Futures run on the global thread pool (see below).
7
-
8
- Futures have three possible states: *pending*, *rejected*, and *fulfilled*. When a future is created it is set
9
- to *pending* and will remain in that state until processing is complete. A completed future is either *rejected*,
10
- indicating that an exception was thrown during processing, or *fulfilled*, indicating succedd. If a future is
11
- *fulfilled* its `value` will be updated to reflect the result of the operation. If *rejected* the `reason` will
12
- be updated with a reference to the thrown exception. The predicate methods `pending?`, `rejected`, and `fulfilled?`
13
- can be called at any time to obtain the state of the future, as can the `state` method, which returns a symbol.
14
-
15
- Retrieving the value of a future is done through the `value` (alias: `deref`) method. Obtaining the value of
16
- a future is a potentially blocking operation. When a future is *rejected* a call to `value` will return `nil`
17
- immediately. When a future is *fulfilled* a call to `value` will immediately return the current value.
18
- When a future is *pending* a call to `value` will block until the future is either *rejected* or *fulfilled*.
19
- A *timeout* value can be passed to `value` to limit how long the call will block. If `nil` the call will
20
- block indefinitely. If `0` the call will not block. Any other integer or float value will indicate the
21
- maximum number of seconds to block.
22
-
23
- ## Examples
24
-
25
- A fulfilled example:
26
-
27
- ```ruby
28
- require 'concurrent'
29
-
30
- count = Concurrent::Future{ sleep(10); 10 }
31
- count.state #=> :pending
32
- count.pending? #=> true
33
-
34
- # do stuff...
35
-
36
- count.value(0) #=> nil (does not block)
37
-
38
- count.value #=> 10 (after blocking)
39
- count.state #=> :fulfilled
40
- count.fulfilled? #=> true
41
- deref count #=> 10
42
- ```
43
-
44
- A rejected example:
45
-
46
- ```ruby
47
- count = future{ sleep(10); raise StandardError.new("Boom!") }
48
- count.state #=> :pending
49
- pending?(count) #=> true
50
-
51
- deref(count) #=> nil (after blocking)
52
- rejected?(count) #=> true
53
- count.reason #=> #<StandardError: Boom!>
54
- ```
55
-
56
- ## Copyright
57
-
58
- *Concurrent Ruby* is Copyright &copy; 2013 [Jerry D'Antonio](https://twitter.com/jerrydantonio).
59
- It is free software and may be redistributed under the terms specified in the LICENSE file.
60
-
61
- ## License
62
-
63
- Released under the MIT license.
64
-
65
- http://www.opensource.org/licenses/mit-license.php
66
-
67
- > Permission is hereby granted, free of charge, to any person obtaining a copy
68
- > of this software and associated documentation files (the "Software"), to deal
69
- > in the Software without restriction, including without limitation the rights
70
- > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
71
- > copies of the Software, and to permit persons to whom the Software is
72
- > furnished to do so, subject to the following conditions:
73
- >
74
- > The above copyright notice and this permission notice shall be included in
75
- > all copies or substantial portions of the Software.
76
- >
77
- > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
78
- > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
79
- > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
80
- > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
81
- > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
82
- > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
83
- > THE SOFTWARE.
1
+ # We're Sending You Back to the Future!
2
+
3
+ Futures are inspired by [Clojure's](http://clojure.org/) [future](http://clojuredocs.org/clojure_core/clojure.core/future) keyword.
4
+ A future represents a promise to complete an action at some time in the future. The action is atomic and permanent.
5
+ The idea behind a future is to send an action off for asynchronous operation, do other stuff, then return and
6
+ retrieve the result of the async operation at a later time. Futures run on the global thread pool (see below).
7
+
8
+ Futures have three possible states: *pending*, *rejected*, and *fulfilled*. When a future is created it is set
9
+ to *pending* and will remain in that state until processing is complete. A completed future is either *rejected*,
10
+ indicating that an exception was thrown during processing, or *fulfilled*, indicating succedd. If a future is
11
+ *fulfilled* its `value` will be updated to reflect the result of the operation. If *rejected* the `reason` will
12
+ be updated with a reference to the thrown exception. The predicate methods `pending?`, `rejected`, and `fulfilled?`
13
+ can be called at any time to obtain the state of the future, as can the `state` method, which returns a symbol.
14
+
15
+ Retrieving the value of a future is done through the `value` (alias: `deref`) method. Obtaining the value of
16
+ a future is a potentially blocking operation. When a future is *rejected* a call to `value` will return `nil`
17
+ immediately. When a future is *fulfilled* a call to `value` will immediately return the current value.
18
+ When a future is *pending* a call to `value` will block until the future is either *rejected* or *fulfilled*.
19
+ A *timeout* value can be passed to `value` to limit how long the call will block. If `nil` the call will
20
+ block indefinitely. If `0` the call will not block. Any other integer or float value will indicate the
21
+ maximum number of seconds to block.
22
+
23
+ ## Examples
24
+
25
+ A fulfilled example:
26
+
27
+ ```ruby
28
+ require 'concurrent'
29
+
30
+ count = Concurrent::Future{ sleep(10); 10 }
31
+ count.state #=> :pending
32
+ count.pending? #=> true
33
+
34
+ # do stuff...
35
+
36
+ count.value(0) #=> nil (does not block)
37
+
38
+ count.value #=> 10 (after blocking)
39
+ count.state #=> :fulfilled
40
+ count.fulfilled? #=> true
41
+ deref count #=> 10
42
+ ```
43
+
44
+ A rejected example:
45
+
46
+ ```ruby
47
+ count = future{ sleep(10); raise StandardError.new("Boom!") }
48
+ count.state #=> :pending
49
+ pending?(count) #=> true
50
+
51
+ deref(count) #=> nil (after blocking)
52
+ rejected?(count) #=> true
53
+ count.reason #=> #<StandardError: Boom!>
54
+ ```
55
+
56
+ ## Copyright
57
+
58
+ *Concurrent Ruby* is Copyright &copy; 2013 [Jerry D'Antonio](https://twitter.com/jerrydantonio).
59
+ It is free software and may be redistributed under the terms specified in the LICENSE file.
60
+
61
+ ## License
62
+
63
+ Released under the MIT license.
64
+
65
+ http://www.opensource.org/licenses/mit-license.php
66
+
67
+ > Permission is hereby granted, free of charge, to any person obtaining a copy
68
+ > of this software and associated documentation files (the "Software"), to deal
69
+ > in the Software without restriction, including without limitation the rights
70
+ > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
71
+ > copies of the Software, and to permit persons to whom the Software is
72
+ > furnished to do so, subject to the following conditions:
73
+ >
74
+ > The above copyright notice and this permission notice shall be included in
75
+ > all copies or substantial portions of the Software.
76
+ >
77
+ > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
78
+ > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
79
+ > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
80
+ > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
81
+ > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
82
+ > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
83
+ > THE SOFTWARE.
@@ -1,52 +1,52 @@
1
- # Go, Go, Gadget Goroutine!
2
-
3
- A goroutine is the simplest of the concurrency utilities in this library. It is inspired by
4
- [Go's](http://golang.org/) [goroutines](https://gobyexample.com/goroutines) and
5
- [Erlang's](http://www.erlang.org/) [spawn](http://erlangexamples.com/tag/spawn/) keyword. The
6
- `go` function is nothing more than a simple way to send a block to the global thread pool (see below)
7
- for processing.
8
-
9
- ## Examples
10
-
11
- ```ruby
12
- require 'concurrent'
13
-
14
- @expected = nil
15
-
16
- go(1, 2, 3){|a, b, c| sleep(1); @expected = [c, b, a] }
17
-
18
- sleep(0.1)
19
- @expected #=> nil
20
-
21
- sleep(2)
22
- @expected #=> [3, 2, 1]
23
- ```
24
-
25
- ## Copyright
26
-
27
- *Concurrent Ruby* is Copyright &copy; 2013 [Jerry D'Antonio](https://twitter.com/jerrydantonio).
28
- It is free software and may be redistributed under the terms specified in the LICENSE file.
29
-
30
- ## License
31
-
32
- Released under the MIT license.
33
-
34
- http://www.opensource.org/licenses/mit-license.php
35
-
36
- > Permission is hereby granted, free of charge, to any person obtaining a copy
37
- > of this software and associated documentation files (the "Software"), to deal
38
- > in the Software without restriction, including without limitation the rights
39
- > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
40
- > copies of the Software, and to permit persons to whom the Software is
41
- > furnished to do so, subject to the following conditions:
42
- >
43
- > The above copyright notice and this permission notice shall be included in
44
- > all copies or substantial portions of the Software.
45
- >
46
- > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
47
- > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
48
- > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
49
- > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
50
- > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
51
- > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
52
- > THE SOFTWARE.
1
+ # Go, Go, Gadget Goroutine!
2
+
3
+ A goroutine is the simplest of the concurrency utilities in this library. It is inspired by
4
+ [Go's](http://golang.org/) [goroutines](https://gobyexample.com/goroutines) and
5
+ [Erlang's](http://www.erlang.org/) [spawn](http://erlangexamples.com/tag/spawn/) keyword. The
6
+ `go` function is nothing more than a simple way to send a block to the global thread pool (see below)
7
+ for processing.
8
+
9
+ ## Examples
10
+
11
+ ```ruby
12
+ require 'concurrent'
13
+
14
+ @expected = nil
15
+
16
+ go(1, 2, 3){|a, b, c| sleep(1); @expected = [c, b, a] }
17
+
18
+ sleep(0.1)
19
+ @expected #=> nil
20
+
21
+ sleep(2)
22
+ @expected #=> [3, 2, 1]
23
+ ```
24
+
25
+ ## Copyright
26
+
27
+ *Concurrent Ruby* is Copyright &copy; 2013 [Jerry D'Antonio](https://twitter.com/jerrydantonio).
28
+ It is free software and may be redistributed under the terms specified in the LICENSE file.
29
+
30
+ ## License
31
+
32
+ Released under the MIT license.
33
+
34
+ http://www.opensource.org/licenses/mit-license.php
35
+
36
+ > Permission is hereby granted, free of charge, to any person obtaining a copy
37
+ > of this software and associated documentation files (the "Software"), to deal
38
+ > in the Software without restriction, including without limitation the rights
39
+ > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
40
+ > copies of the Software, and to permit persons to whom the Software is
41
+ > furnished to do so, subject to the following conditions:
42
+ >
43
+ > The above copyright notice and this permission notice shall be included in
44
+ > all copies or substantial portions of the Software.
45
+ >
46
+ > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
47
+ > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
48
+ > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
49
+ > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
50
+ > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
51
+ > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
52
+ > THE SOFTWARE.