async_enum 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- ZDFhMWYwZjQ0ZWE1Njc1NzJiZGU3ZTEwMDAyMzIzN2M4ZmZhZDM4ZA==
4
+ OTY4MmYzYjc3ZjgxMDRjNjE5MWM4OGZhYTUzYWQwZmVkMTg4NDc2Mw==
5
5
  data.tar.gz: !binary |-
6
- ZDAzNTI1ZjczYzU4NjQ0YTNhNTVmMTkzMzdjNzEyMzk4Y2Q4ZjUwMw==
6
+ YTY3NjJjYmI1ZGE4NzUxMjNmODJjN2YwMDMxOTYwYzM0NzZjOTFiOA==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- YmQ0MjFmMTU3NGQyMWEzZTQ4MWY5NjM2NGZhMWVhN2Q0OTU4ZGY3ZTBhNDI3
10
- NWUyNmQ1YzZlMWVkNjA0YmIwNWE5OTZhNTdhNzg1ZjUxZTdkZDkxZjUzMzM4
11
- MDA5NmFhZGU3NzE5MTQyMGMzOTU3N2IzNTUxYzczMzgwMzcwNTE=
9
+ OWQ1NzEzMDQ4OGRmYmU2NjE0N2IzZjlkYjcyYTVmNGM5YzQ5NzUzYTZiMjIy
10
+ OThmOGNmZDUxZjdlYjEwOTU2MDlhZWU0YWU1M2ZhNzNkODU2NGU4OTYwNWEw
11
+ YjA0OGFkMWYyNDYzZGM1NTkwOTNlMTc5ZDg0Zjc2YzJmNzEwZmE=
12
12
  data.tar.gz: !binary |-
13
- ZjdiNzk0OWI1MGI0YzE1MzE5NjExYzI4OTNjNGYzNmM1YzQ0ZmViODk0NTA0
14
- OWMyZWUyNjQwOTY5MzdlYzEzZjc2OThjNWVhZGExYWE1MzI2MmQ4NTM4M2Zj
15
- YmZlMmFhMjljNTk1ODVhYWIxZTY2MTIwOWUyNDQ3MmQ1ZjRkZDc=
13
+ MTVmZjc3M2JhYmEwNTMxMjQzNGY1NWM0Y2UwYWExMmM4NzNjMTQ4NWI4ZDU3
14
+ NTRkYTI0ZjdkYjhmYjcyYzg0NTE3YTQyOTVmZGZjYTlmMDNlMWNjMzEyMjE3
15
+ NjM3ZDMxMjhlY2RhNmNmNjMzNTcxOWM3ZmE0OWJhNjNhODY2NGM=
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # async\_enum
1
+ # async\_enum ![](https://travis-ci.org/aj0strow/async_enum.png)
2
2
 
3
3
  Inspired by Enumerable#lazy coupled with Enumerator::Lazy, and the Async.js library, I thought it would be cool to have syntax like `urls.async.map{ |url| http_get(url) }`.
4
4
 
@@ -83,12 +83,15 @@ end
83
83
 
84
84
  #### Preventing race conditions
85
85
 
86
- When programming concurrently, nasty bugs can come up because some operations aren't atomic. For instance, incrementing a variable `x += 1` will not necessarily work as expected. To provide easy locking, there's a DSL-style `lock` method you can use in the block passed to the async enum.
86
+ When programming concurrently, nasty bugs can come up because some operations aren't atomic. For instance, incrementing a variable `x += 1` will not necessarily work as expected. Use a lock when encountering these types of errors.
87
87
 
88
88
  ```ruby
89
+ require 'async_enum'
90
+
89
91
  count = 0
92
+ mutex = Mutex.new
90
93
  ('a'..'z').async.each do
91
- lock :count do
94
+ mutex.synchronize do
92
95
  count += 1
93
96
  end
94
97
  end
@@ -96,7 +99,7 @@ count
96
99
  # => 26
97
100
  ```
98
101
 
99
- The name of the lock doesn't matter, but using the variable name helps make the code understandable. You should try to use 1 lock per thread-unsafe variable.
102
+ There used to be a lock DSL syntax, but it ruined using async_enum in scoped method calls.
100
103
 
101
104
  ## Notes
102
105
 
@@ -116,6 +119,12 @@ $ cd async_enum
116
119
  $ ruby -I lib demos/sleep.rb
117
120
  ```
118
121
 
119
- **Disclaimer**: I am not an expert at multithreading. Quite the opposite in fact.
122
+ #### Contributions
123
+
124
+ * Yoshida Tetsuya ([@yoshida-eth0](https://github.com/yoshida-eth0)) fixed the fiber error issue, and made the gem work with hashes.
120
125
 
121
126
  Please report errors and feel free to contribute and improve things!
127
+
128
+
129
+ [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/aj0strow/async_enum/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
130
+
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
 
5
5
  Gem::Specification.new do |s|
6
6
  s.name = 'async_enum'
7
- s.version = '0.0.5'
7
+ s.version = '0.0.6'
8
8
  s.authors = %w(aj0strow)
9
9
  s.email = 'alexander.ostrow@gmail.com'
10
10
  s.description = 'iterate over enumerable objects concurrently'
@@ -1,8 +1,9 @@
1
1
  require 'async_enum'
2
2
 
3
3
  count = 0
4
+ mutex = Mutex.new
4
5
  ('a'..'z').async.each do
5
- lock :count do
6
+ mutex.synchronize do
6
7
  count += 1
7
8
  end
8
9
  end
@@ -2,7 +2,7 @@ require 'benchmark'
2
2
  require 'async_enum'
3
3
 
4
4
  default = Benchmark.measure do
5
- 500.times.async.each{ true }
5
+ 500.times.async.each{ true }
6
6
  end
7
7
 
8
8
  limited = Benchmark.measure do
@@ -2,7 +2,7 @@ require 'benchmark'
2
2
  require 'async_enum'
3
3
 
4
4
  sync = Benchmark.measure do
5
- 5.times{ sleep 0.1 }
5
+ 5.times{ sleep 0.1 }
6
6
  end
7
7
 
8
8
  async = Benchmark.measure do
@@ -3,35 +3,17 @@ require 'thread'
3
3
  class Enumerator
4
4
  class Async < Enumerator
5
5
 
6
- class Lockset
7
- def initialize
8
- @semaphores = Hash.new do |locks, key|
9
- locks[key] = Mutex.new
10
- end
11
- end
12
-
13
- def lock(key = :__default__, &thread_unsafe_block)
14
- @semaphores[key].synchronize(&thread_unsafe_block)
15
- end
16
-
17
- alias_method :evaluate, :instance_exec
18
- end
19
-
20
6
  EOQ = Object.new
21
7
  private_constant :EOQ
22
8
 
23
9
  def initialize(enum, pool_size = nil)
24
- if pool_size
25
- unless pool_size >= 1
26
- message = "Thread pool size is invalid! Expected a positive integer but got: #{pool_size}"
27
- raise ArgumentError, message
28
- end
29
- pool_size = pool_size.to_i
10
+ pool_size = (pool_size || enum.count).to_i
11
+ unless pool_size >= 1
12
+ message = "Thread pool size is invalid! Expected a positive integer but got: #{pool_size}"
13
+ raise ArgumentError, message
30
14
  end
31
15
 
32
- @enum = enum
33
- @pool_size = pool_size
34
- @lockset = Lockset.new
16
+ @enum, @pool_size = enum, pool_size
35
17
  end
36
18
 
37
19
  def to_a
@@ -41,86 +23,59 @@ class Enumerator
41
23
  def sync
42
24
  @enum
43
25
  end
44
-
45
26
  alias_method :to_enum, :sync
46
27
 
47
28
  def size
48
29
  @enum.size
49
30
  end
50
31
 
51
- def each(&work)
52
- raise_error('each') unless block_given?
32
+ def each
33
+ raise_error(:each) unless block_given?
53
34
 
54
- if @pool_size
55
- queue = SizedQueue.new @pool_size
56
-
57
- threads = @pool_size.times.map do
58
- Thread.new do
59
- loop do
60
- item = queue.pop
61
- item != EOQ ? evaluate(item, &work) : break
62
- end
35
+ queue = SizedQueue.new @pool_size
36
+
37
+ threads = @pool_size.times.map do
38
+ Thread.new do
39
+ loop do
40
+ item = queue.pop
41
+ item != EOQ ? yield(item) : break
63
42
  end
64
43
  end
65
-
66
- begin
67
- loop { queue.push @enum.next }
68
- rescue StopIteration
69
- ensure
70
- @pool_size.times { queue.push EOQ }
71
- end
72
-
73
- threads.each(&:join)
74
- @enum.rewind
75
- else
76
- unlimited_threads(&work).each(&:join)
77
44
  end
45
+
46
+ begin
47
+ loop { queue.push @enum.next }
48
+ rescue StopIteration
49
+ ensure
50
+ @pool_size.times { queue.push EOQ }
51
+ end
52
+
53
+ threads.each(&:join)
54
+ @enum.rewind
78
55
  self
79
56
  end
80
57
 
81
58
  def with_index(start = 0, &work)
82
59
  @enum = @enum.with_index(start)
83
- if block_given?
84
- each(&work)
85
- else
86
- self
87
- end
60
+ block_given? ? each(&work) : self
88
61
  end
89
62
 
90
- def with_object(obj, &work)
91
- @enum = @enum.with_object(obj)
92
- if block_given?
93
- each(&work); obj
94
- else
95
- self
96
- end
63
+ def with_object(object, &work)
64
+ @enum = @enum.with_object(object)
65
+ block_given? ? (each(&work) and object) : self
97
66
  end
98
67
 
99
- def map(&work)
100
- raise_error('map') unless block_given?
68
+ def map
69
+ raise_error(:map) unless block_given?
101
70
 
102
- if @pool_size
103
- outs = []
71
+ [].tap do |outs|
104
72
  with_index do |item, index|
105
- outs[index] = evaluate(item, &work)
73
+ outs[index] = yield(item)
106
74
  end
107
- outs
108
- else
109
- unlimited_threads(&work).map(&:value)
110
75
  end
111
76
  end
112
77
 
113
78
  private
114
-
115
- def evaluate(*args, &work)
116
- @lockset.instance_exec(*args, &work)
117
- end
118
-
119
- def unlimited_threads(&work)
120
- @enum.map do |*args|
121
- Thread.new{ evaluate(*args, &work) }
122
- end
123
- end
124
79
 
125
80
  def raise_error(method)
126
81
  raise ArgumentError, "Tried to call async #{method} without a block"
@@ -87,15 +87,5 @@ class EnumeratorAsyncTest < Test
87
87
  strs = @enum.map{ |i| sleep rand; i.to_s }
88
88
  assert_equal '1 2 3 4 5', strs.join(' ')
89
89
  end
90
-
91
- test 'lock in block' do
92
- count = 0
93
- 1000.times.async(5).each do
94
- lock :count do
95
- count += 1
96
- end
97
- end
98
- assert_equal 1000, count
99
- end
100
90
 
101
91
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: async_enum
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - aj0strow
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-10-29 00:00:00.000000000 Z
11
+ date: 2014-01-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler