async-enumerable 0.1.0
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/.rspec +3 -0
- data/.standard.yml +5 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/LICENSE.txt +21 -0
- data/README.md +416 -0
- data/Rakefile +127 -0
- data/benchmark/async_all.yaml +38 -0
- data/benchmark/async_any.yaml +39 -0
- data/benchmark/async_each.yaml +51 -0
- data/benchmark/async_find.yaml +37 -0
- data/benchmark/async_map.yaml +50 -0
- data/benchmark/async_select.yaml +31 -0
- data/benchmark/early_termination/any_early.yaml +17 -0
- data/benchmark/early_termination/any_late.yaml +17 -0
- data/benchmark/early_termination/find_middle.yaml +17 -0
- data/benchmark/size_comparison/map_10.yaml +17 -0
- data/benchmark/size_comparison/map_100.yaml +17 -0
- data/benchmark/size_comparison/map_1000.yaml +20 -0
- data/benchmark/size_comparison/map_10000.yaml +23 -0
- data/docs/reference/README.md +43 -0
- data/docs/reference/concurrency_bounder.md +234 -0
- data/docs/reference/enumerable.md +258 -0
- data/docs/reference/enumerator.md +221 -0
- data/docs/reference/methods/converters.md +97 -0
- data/docs/reference/methods/predicates.md +254 -0
- data/docs/reference/methods/transformers.md +104 -0
- data/lib/async/enumerable/comparable.rb +26 -0
- data/lib/async/enumerable/concurrency_bounder.rb +37 -0
- data/lib/async/enumerable/configurable.rb +140 -0
- data/lib/async/enumerable/methods/aggregators.rb +40 -0
- data/lib/async/enumerable/methods/converters.rb +21 -0
- data/lib/async/enumerable/methods/each.rb +39 -0
- data/lib/async/enumerable/methods/iterators.rb +27 -0
- data/lib/async/enumerable/methods/predicates/all.rb +47 -0
- data/lib/async/enumerable/methods/predicates/any.rb +47 -0
- data/lib/async/enumerable/methods/predicates/find.rb +55 -0
- data/lib/async/enumerable/methods/predicates/find_index.rb +50 -0
- data/lib/async/enumerable/methods/predicates/include.rb +23 -0
- data/lib/async/enumerable/methods/predicates/none.rb +27 -0
- data/lib/async/enumerable/methods/predicates/one.rb +48 -0
- data/lib/async/enumerable/methods/predicates.rb +29 -0
- data/lib/async/enumerable/methods/slicers.rb +34 -0
- data/lib/async/enumerable/methods/transformers/compact.rb +18 -0
- data/lib/async/enumerable/methods/transformers/filter_map.rb +19 -0
- data/lib/async/enumerable/methods/transformers/flat_map.rb +20 -0
- data/lib/async/enumerable/methods/transformers/map.rb +22 -0
- data/lib/async/enumerable/methods/transformers/reject.rb +19 -0
- data/lib/async/enumerable/methods/transformers/select.rb +21 -0
- data/lib/async/enumerable/methods/transformers/sort.rb +18 -0
- data/lib/async/enumerable/methods/transformers/sort_by.rb +19 -0
- data/lib/async/enumerable/methods/transformers/uniq.rb +18 -0
- data/lib/async/enumerable/methods/transformers.rb +35 -0
- data/lib/async/enumerable/methods.rb +26 -0
- data/lib/async/enumerable/version.rb +10 -0
- data/lib/async/enumerable.rb +72 -0
- data/lib/async/enumerator.rb +33 -0
- data/lib/enumerable/async.rb +38 -0
- data/scripts/debug_config.rb +26 -0
- data/scripts/debug_config2.rb +34 -0
- data/scripts/sketch.rb +30 -0
- data/scripts/test_aggregators.rb +66 -0
- data/scripts/test_ancestors.rb +12 -0
- data/scripts/test_async_chaining.rb +30 -0
- data/scripts/test_direct_method_calls.rb +53 -0
- data/scripts/test_example.rb +37 -0
- data/scripts/test_issue_7.rb +69 -0
- data/scripts/test_method_source.rb +15 -0
- metadata +145 -0
data/Rakefile
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/gem_tasks"
|
4
|
+
require "rspec/core/rake_task"
|
5
|
+
|
6
|
+
RSpec::Core::RakeTask.new(:spec)
|
7
|
+
|
8
|
+
require "standard/rake"
|
9
|
+
|
10
|
+
task default: %i[spec standard]
|
11
|
+
|
12
|
+
desc "Run quick benchmark overview"
|
13
|
+
task :benchmark_quick do
|
14
|
+
require "benchmark"
|
15
|
+
require_relative "lib/async/enumerable"
|
16
|
+
|
17
|
+
# Simulate IO operations with random delays
|
18
|
+
def io_operation(n)
|
19
|
+
sleep(rand / 1000.0) # Sleep 0-1ms to simulate IO
|
20
|
+
n * 2
|
21
|
+
end
|
22
|
+
|
23
|
+
def expensive_check(n)
|
24
|
+
sleep(rand / 1000.0) # Sleep 0-1ms to simulate IO
|
25
|
+
n % 10 == 0
|
26
|
+
end
|
27
|
+
|
28
|
+
puts "Async::Enumerable Benchmark Comparison"
|
29
|
+
puts "=" * 50
|
30
|
+
puts "Simulating IO operations with 0-1ms delays"
|
31
|
+
puts
|
32
|
+
|
33
|
+
# Test different array sizes
|
34
|
+
[10, 100, 1000, 10000].each do |size|
|
35
|
+
array = (1..size).to_a
|
36
|
+
|
37
|
+
puts "\nArray size: #{size} elements"
|
38
|
+
puts "-" * 30
|
39
|
+
|
40
|
+
Benchmark.bm(20) do |x|
|
41
|
+
# Map benchmark
|
42
|
+
x.report("sync map:") do
|
43
|
+
array.map { |n| io_operation(n) }
|
44
|
+
end
|
45
|
+
|
46
|
+
x.report("async map:") do
|
47
|
+
array.async.map { |n| io_operation(n) }
|
48
|
+
end
|
49
|
+
|
50
|
+
# For very large collections, also test with custom max_fibers
|
51
|
+
if size >= 1000
|
52
|
+
x.report("async map (100f):") do
|
53
|
+
array.async(max_fibers: 100).map { |n| io_operation(n) }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Select benchmark
|
58
|
+
x.report("sync select:") do
|
59
|
+
array.select { |n| expensive_check(n) }
|
60
|
+
end
|
61
|
+
|
62
|
+
x.report("async select:") do
|
63
|
+
array.async.select { |n| expensive_check(n) }
|
64
|
+
end
|
65
|
+
|
66
|
+
# Any? benchmark (with early termination)
|
67
|
+
x.report("sync any?:") do
|
68
|
+
array.any? { |n| expensive_check(n) }
|
69
|
+
end
|
70
|
+
|
71
|
+
x.report("async any?:") do
|
72
|
+
array.async.any? { |n| expensive_check(n) }
|
73
|
+
end
|
74
|
+
|
75
|
+
# Find benchmark (with early termination)
|
76
|
+
target = size / 2
|
77
|
+
x.report("sync find:") do
|
78
|
+
array.find { |n| n == target }
|
79
|
+
end
|
80
|
+
|
81
|
+
x.report("async find:") do
|
82
|
+
array.async.find { |n|
|
83
|
+
sleep(rand / 1000.0)
|
84
|
+
n == target
|
85
|
+
}
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
puts "\n" + "=" * 50
|
91
|
+
puts "Note: Async methods show performance benefits when:"
|
92
|
+
puts " - Operations involve IO (network, disk, etc.)"
|
93
|
+
puts " - Collection size is large enough to offset async overhead"
|
94
|
+
end
|
95
|
+
|
96
|
+
desc "Run detailed benchmarks with clear comparisons"
|
97
|
+
task :benchmark do
|
98
|
+
puts "=" * 80
|
99
|
+
puts "Async::Enumerable Benchmarks"
|
100
|
+
puts "=" * 80
|
101
|
+
puts
|
102
|
+
|
103
|
+
# Size comparison benchmarks
|
104
|
+
puts "📊 varying collection sizes"
|
105
|
+
puts "-" * 40
|
106
|
+
puts "\nThese benchmarks compare sync vs async performance across different collection sizes."
|
107
|
+
puts "IO operations are simulated with sleep delays.\n\n"
|
108
|
+
|
109
|
+
Dir.glob("benchmark/size_comparison/*.yaml").sort.each do |file|
|
110
|
+
size = File.basename(file, ".yaml").split("_").last
|
111
|
+
puts "\nCollection Size: #{size} items"
|
112
|
+
system("bundle exec benchmark-driver #{file} 2>/dev/null")
|
113
|
+
end
|
114
|
+
|
115
|
+
# Early termination benchmarks
|
116
|
+
puts "\n\n" + "=" * 80
|
117
|
+
puts "⚡ early termination benchmarks"
|
118
|
+
puts "-" * 40
|
119
|
+
puts "\nThese benchmarks test methods that can terminate early (any?, find, etc.)."
|
120
|
+
puts "They demonstrate async performance benefits even with early termination.\n\n"
|
121
|
+
|
122
|
+
Dir.glob("benchmark/early_termination/*.yaml").sort.each do |file|
|
123
|
+
name = File.basename(file, ".yaml").tr("_", " ")
|
124
|
+
puts "\n#{name}"
|
125
|
+
system("bundle exec benchmark-driver #{file} 2>/dev/null")
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
prelude: |
|
2
|
+
require 'async/enumerable'
|
3
|
+
|
4
|
+
# Simulate IO operation for validation
|
5
|
+
def valid_item?(n, max_value = 1000)
|
6
|
+
sleep(rand / 1000.0) # Sleep 0-1ms to simulate IO
|
7
|
+
n < max_value
|
8
|
+
end
|
9
|
+
|
10
|
+
all_valid = (1..50).to_a
|
11
|
+
early_invalid = [1, 2, 1001, 4, 5] + (6..50).to_a # Invalid at position 3
|
12
|
+
mid_invalid = (1..25).to_a + [1001] + (27..50).to_a # Invalid at middle
|
13
|
+
late_invalid = (1..49).to_a + [1001] # Invalid at end
|
14
|
+
|
15
|
+
benchmark:
|
16
|
+
sync_all_valid: |
|
17
|
+
all_valid.all? { |n| valid_item?(n) }
|
18
|
+
|
19
|
+
async_all_valid: |
|
20
|
+
all_valid.async.all? { |n| valid_item?(n) }
|
21
|
+
|
22
|
+
sync_early_fail: |
|
23
|
+
early_invalid.all? { |n| valid_item?(n) }
|
24
|
+
|
25
|
+
async_early_fail: |
|
26
|
+
early_invalid.async.all? { |n| valid_item?(n) }
|
27
|
+
|
28
|
+
sync_mid_fail: |
|
29
|
+
mid_invalid.all? { |n| valid_item?(n) }
|
30
|
+
|
31
|
+
async_mid_fail: |
|
32
|
+
mid_invalid.async.all? { |n| valid_item?(n) }
|
33
|
+
|
34
|
+
sync_late_fail: |
|
35
|
+
late_invalid.all? { |n| valid_item?(n) }
|
36
|
+
|
37
|
+
async_late_fail: |
|
38
|
+
late_invalid.async.all? { |n| valid_item?(n) }
|
@@ -0,0 +1,39 @@
|
|
1
|
+
prelude: |
|
2
|
+
require 'async/enumerable'
|
3
|
+
|
4
|
+
# Simulate IO operation with early termination potential
|
5
|
+
def expensive_check(n, target)
|
6
|
+
sleep(rand / 1000.0) # Sleep 0-1ms to simulate IO
|
7
|
+
n == target
|
8
|
+
end
|
9
|
+
|
10
|
+
# Arrays with target at different positions
|
11
|
+
early_match = (1..100).to_a # Target at position 10
|
12
|
+
mid_match = (1..100).to_a # Target at position 50
|
13
|
+
late_match = (1..100).to_a # Target at position 90
|
14
|
+
no_match = (1..100).to_a # No target
|
15
|
+
|
16
|
+
benchmark:
|
17
|
+
sync_early: |
|
18
|
+
early_match.any? { |n| expensive_check(n, 10) }
|
19
|
+
|
20
|
+
async_early: |
|
21
|
+
early_match.async.any? { |n| expensive_check(n, 10) }
|
22
|
+
|
23
|
+
sync_mid: |
|
24
|
+
mid_match.any? { |n| expensive_check(n, 50) }
|
25
|
+
|
26
|
+
async_mid: |
|
27
|
+
mid_match.async.any? { |n| expensive_check(n, 50) }
|
28
|
+
|
29
|
+
sync_late: |
|
30
|
+
late_match.any? { |n| expensive_check(n, 90) }
|
31
|
+
|
32
|
+
async_late: |
|
33
|
+
late_match.async.any? { |n| expensive_check(n, 90) }
|
34
|
+
|
35
|
+
sync_no_match: |
|
36
|
+
no_match.any? { |n| expensive_check(n, 200) }
|
37
|
+
|
38
|
+
async_no_match: |
|
39
|
+
no_match.async.any? { |n| expensive_check(n, 200) }
|
@@ -0,0 +1,51 @@
|
|
1
|
+
prelude: |
|
2
|
+
require 'async/enumerable'
|
3
|
+
|
4
|
+
# Simulate IO side effect operation
|
5
|
+
# Scale down delay for larger collections to avoid timeouts
|
6
|
+
def process_item(n, size = 100)
|
7
|
+
delay = case size
|
8
|
+
when 1..100 then rand / 1000.0 # 0-1ms
|
9
|
+
when 101..1000 then rand / 5000.0 # 0-0.2ms
|
10
|
+
else rand / 50000.0 # 0-0.02ms for 10000
|
11
|
+
end
|
12
|
+
sleep(delay)
|
13
|
+
# Side effect: would normally write to file, database, etc.
|
14
|
+
n * 2
|
15
|
+
end
|
16
|
+
|
17
|
+
array_10 = (1..10).to_a
|
18
|
+
array_100 = (1..100).to_a
|
19
|
+
array_1000 = (1..1000).to_a
|
20
|
+
array_10000 = (1..10000).to_a
|
21
|
+
|
22
|
+
benchmark:
|
23
|
+
sync_10: |
|
24
|
+
array_10.each { |n| process_item(n, 10) }
|
25
|
+
|
26
|
+
async_10: |
|
27
|
+
array_10.async.each { |n| process_item(n, 10) }
|
28
|
+
|
29
|
+
sync_100: |
|
30
|
+
array_100.each { |n| process_item(n, 100) }
|
31
|
+
|
32
|
+
async_100: |
|
33
|
+
array_100.async.each { |n| process_item(n, 100) }
|
34
|
+
|
35
|
+
sync_1000: |
|
36
|
+
array_1000.each { |n| process_item(n, 1000) }
|
37
|
+
|
38
|
+
async_1000: |
|
39
|
+
array_1000.async.each { |n| process_item(n, 1000) }
|
40
|
+
|
41
|
+
async_1000_limited: |
|
42
|
+
array_1000.async(max_fibers: 100).each { |n| process_item(n, 1000) }
|
43
|
+
|
44
|
+
sync_10000: |
|
45
|
+
array_10000.each { |n| process_item(n, 10000) }
|
46
|
+
|
47
|
+
async_10000: |
|
48
|
+
array_10000.async.each { |n| process_item(n, 10000) }
|
49
|
+
|
50
|
+
async_10000_limited: |
|
51
|
+
array_10000.async(max_fibers: 100).each { |n| process_item(n, 10000) }
|
@@ -0,0 +1,37 @@
|
|
1
|
+
prelude: |
|
2
|
+
require 'async/enumerable'
|
3
|
+
|
4
|
+
# Simulate IO operation for finding an item
|
5
|
+
def matches_criteria(n, target)
|
6
|
+
sleep(rand / 1000.0) # Sleep 0-1ms to simulate IO
|
7
|
+
n == target
|
8
|
+
end
|
9
|
+
|
10
|
+
small_array = (1..20).to_a
|
11
|
+
medium_array = (1..100).to_a
|
12
|
+
large_array = (1..500).to_a
|
13
|
+
|
14
|
+
benchmark:
|
15
|
+
sync_small_early: |
|
16
|
+
small_array.find { |n| matches_criteria(n, 5) }
|
17
|
+
|
18
|
+
async_small_early: |
|
19
|
+
small_array.async.find { |n| matches_criteria(n, 5) }
|
20
|
+
|
21
|
+
sync_medium_mid: |
|
22
|
+
medium_array.find { |n| matches_criteria(n, 50) }
|
23
|
+
|
24
|
+
async_medium_mid: |
|
25
|
+
medium_array.async.find { |n| matches_criteria(n, 50) }
|
26
|
+
|
27
|
+
sync_large_late: |
|
28
|
+
large_array.find { |n| matches_criteria(n, 450) }
|
29
|
+
|
30
|
+
async_large_late: |
|
31
|
+
large_array.async.find { |n| matches_criteria(n, 450) }
|
32
|
+
|
33
|
+
sync_not_found: |
|
34
|
+
medium_array.find { |n| matches_criteria(n, 1000) }
|
35
|
+
|
36
|
+
async_not_found: |
|
37
|
+
medium_array.async.find { |n| matches_criteria(n, 1000) }
|
@@ -0,0 +1,50 @@
|
|
1
|
+
prelude: |
|
2
|
+
require 'async/enumerable'
|
3
|
+
|
4
|
+
# Simulate IO operations with varying delays
|
5
|
+
# Scale down delay for larger collections to avoid timeouts
|
6
|
+
def io_operation(n, size = 100)
|
7
|
+
delay = case size
|
8
|
+
when 1..100 then rand / 1000.0 # 0-1ms
|
9
|
+
when 101..1000 then rand / 5000.0 # 0-0.2ms
|
10
|
+
else rand / 50000.0 # 0-0.02ms for 10000
|
11
|
+
end
|
12
|
+
sleep(delay)
|
13
|
+
n * 2
|
14
|
+
end
|
15
|
+
|
16
|
+
array_10 = (1..10).to_a
|
17
|
+
array_100 = (1..100).to_a
|
18
|
+
array_1000 = (1..1000).to_a
|
19
|
+
array_10000 = (1..10000).to_a
|
20
|
+
|
21
|
+
benchmark:
|
22
|
+
sync_10: |
|
23
|
+
array_10.map { |n| io_operation(n, 10) }
|
24
|
+
|
25
|
+
async_10: |
|
26
|
+
array_10.async.map { |n| io_operation(n, 10) }
|
27
|
+
|
28
|
+
sync_100: |
|
29
|
+
array_100.map { |n| io_operation(n, 100) }
|
30
|
+
|
31
|
+
async_100: |
|
32
|
+
array_100.async.map { |n| io_operation(n, 100) }
|
33
|
+
|
34
|
+
sync_1000: |
|
35
|
+
array_1000.map { |n| io_operation(n, 1000) }
|
36
|
+
|
37
|
+
async_1000: |
|
38
|
+
array_1000.async.map { |n| io_operation(n, 1000) }
|
39
|
+
|
40
|
+
async_1000_limited: |
|
41
|
+
array_1000.async(max_fibers: 100).map { |n| io_operation(n, 1000) }
|
42
|
+
|
43
|
+
sync_10000: |
|
44
|
+
array_10000.map { |n| io_operation(n, 10000) }
|
45
|
+
|
46
|
+
async_10000: |
|
47
|
+
array_10000.async.map { |n| io_operation(n, 10000) }
|
48
|
+
|
49
|
+
async_10000_limited: |
|
50
|
+
array_10000.async(max_fibers: 100).map { |n| io_operation(n, 10000) }
|
@@ -0,0 +1,31 @@
|
|
1
|
+
prelude: |
|
2
|
+
require 'async/enumerable'
|
3
|
+
|
4
|
+
# Simulate IO operation that checks a condition
|
5
|
+
def check_condition(n)
|
6
|
+
sleep(rand / 1000.0) # Sleep 0-1ms to simulate IO
|
7
|
+
n % 3 == 0
|
8
|
+
end
|
9
|
+
|
10
|
+
small_array = (1..20).to_a
|
11
|
+
medium_array = (1..100).to_a
|
12
|
+
large_array = (1..500).to_a
|
13
|
+
|
14
|
+
benchmark:
|
15
|
+
sync_small: |
|
16
|
+
small_array.select { |n| check_condition(n) }
|
17
|
+
|
18
|
+
async_small: |
|
19
|
+
small_array.async.select { |n| check_condition(n) }
|
20
|
+
|
21
|
+
sync_medium: |
|
22
|
+
medium_array.select { |n| check_condition(n) }
|
23
|
+
|
24
|
+
async_medium: |
|
25
|
+
medium_array.async.select { |n| check_condition(n) }
|
26
|
+
|
27
|
+
sync_large: |
|
28
|
+
large_array.select { |n| check_condition(n) }
|
29
|
+
|
30
|
+
async_large: |
|
31
|
+
large_array.async.select { |n| check_condition(n) }
|
@@ -0,0 +1,17 @@
|
|
1
|
+
prelude: |
|
2
|
+
require 'async/enumerable'
|
3
|
+
|
4
|
+
# Simulate IO operation for checking
|
5
|
+
def expensive_check(n)
|
6
|
+
sleep(rand / 1000.0) # 0-1ms delay
|
7
|
+
n > 5 # Will match early in the array
|
8
|
+
end
|
9
|
+
|
10
|
+
array = (1..100).to_a
|
11
|
+
|
12
|
+
benchmark:
|
13
|
+
"Sync any? (early match)": |
|
14
|
+
array.any? { |n| expensive_check(n) }
|
15
|
+
|
16
|
+
"Async any? (early match)": |
|
17
|
+
array.async.any? { |n| expensive_check(n) }
|
@@ -0,0 +1,17 @@
|
|
1
|
+
prelude: |
|
2
|
+
require 'async/enumerable'
|
3
|
+
|
4
|
+
# Simulate IO operation for checking
|
5
|
+
def expensive_check(n)
|
6
|
+
sleep(rand / 1000.0) # 0-1ms delay
|
7
|
+
n > 95 # Will match late in the array
|
8
|
+
end
|
9
|
+
|
10
|
+
array = (1..100).to_a
|
11
|
+
|
12
|
+
benchmark:
|
13
|
+
"Sync any? (late match)": |
|
14
|
+
array.any? { |n| expensive_check(n) }
|
15
|
+
|
16
|
+
"Async any? (late match)": |
|
17
|
+
array.async.any? { |n| expensive_check(n) }
|
@@ -0,0 +1,17 @@
|
|
1
|
+
prelude: |
|
2
|
+
require 'async/enumerable'
|
3
|
+
|
4
|
+
# Simulate IO operation for searching
|
5
|
+
def matches_criteria?(n)
|
6
|
+
sleep(rand / 1000.0) # 0-1ms delay
|
7
|
+
n == 50 # Will find in the middle
|
8
|
+
end
|
9
|
+
|
10
|
+
array = (1..100).to_a
|
11
|
+
|
12
|
+
benchmark:
|
13
|
+
"Sync find (middle)": |
|
14
|
+
array.find { |n| matches_criteria?(n) }
|
15
|
+
|
16
|
+
"Async find (middle)": |
|
17
|
+
array.async.find { |n| matches_criteria?(n) }
|
@@ -0,0 +1,17 @@
|
|
1
|
+
prelude: |
|
2
|
+
require 'async/enumerable'
|
3
|
+
|
4
|
+
# Simulate IO operations with 0-1ms delay
|
5
|
+
def io_operation(n)
|
6
|
+
sleep(rand / 1000.0)
|
7
|
+
n * 2
|
8
|
+
end
|
9
|
+
|
10
|
+
array = (1..10).to_a
|
11
|
+
|
12
|
+
benchmark:
|
13
|
+
"Sync (10 items)": |
|
14
|
+
array.map { |n| io_operation(n) }
|
15
|
+
|
16
|
+
"Async (10 items)": |
|
17
|
+
array.async.map { |n| io_operation(n) }
|
@@ -0,0 +1,17 @@
|
|
1
|
+
prelude: |
|
2
|
+
require 'async/enumerable'
|
3
|
+
|
4
|
+
# Simulate IO operations with 0-1ms delay
|
5
|
+
def io_operation(n)
|
6
|
+
sleep(rand / 1000.0)
|
7
|
+
n * 2
|
8
|
+
end
|
9
|
+
|
10
|
+
array = (1..100).to_a
|
11
|
+
|
12
|
+
benchmark:
|
13
|
+
"Sync (100 items)": |
|
14
|
+
array.map { |n| io_operation(n) }
|
15
|
+
|
16
|
+
"Async (100 items)": |
|
17
|
+
array.async.map { |n| io_operation(n) }
|
@@ -0,0 +1,20 @@
|
|
1
|
+
prelude: |
|
2
|
+
require 'async/enumerable'
|
3
|
+
|
4
|
+
# Simulate IO operations with reduced delay for large collections
|
5
|
+
def io_operation(n)
|
6
|
+
sleep(rand / 5000.0) # 0-0.2ms
|
7
|
+
n * 2
|
8
|
+
end
|
9
|
+
|
10
|
+
array = (1..1000).to_a
|
11
|
+
|
12
|
+
benchmark:
|
13
|
+
"Sync (1000 items)": |
|
14
|
+
array.map { |n| io_operation(n) }
|
15
|
+
|
16
|
+
"Async (1000 items)": |
|
17
|
+
array.async.map { |n| io_operation(n) }
|
18
|
+
|
19
|
+
"Async(100f) (1000 items)": |
|
20
|
+
array.async(max_fibers: 100).map { |n| io_operation(n) }
|
@@ -0,0 +1,23 @@
|
|
1
|
+
prelude: |
|
2
|
+
require 'async/enumerable'
|
3
|
+
|
4
|
+
# Simulate IO operations with minimal delay for very large collections
|
5
|
+
def io_operation(n)
|
6
|
+
sleep(rand / 50000.0) # 0-0.02ms
|
7
|
+
n * 2
|
8
|
+
end
|
9
|
+
|
10
|
+
array = (1..10000).to_a
|
11
|
+
|
12
|
+
benchmark:
|
13
|
+
"Sync (10000 items)": |
|
14
|
+
array.map { |n| io_operation(n) }
|
15
|
+
|
16
|
+
"Async (10000 items)": |
|
17
|
+
array.async.map { |n| io_operation(n) }
|
18
|
+
|
19
|
+
"Async(100f) (10000 items)": |
|
20
|
+
array.async(max_fibers: 100).map { |n| io_operation(n) }
|
21
|
+
|
22
|
+
"Async(500f) (10000 items)": |
|
23
|
+
array.async(max_fibers: 500).map { |n| io_operation(n) }
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# Async::Enumerable Reference Documentation
|
2
|
+
|
3
|
+
This directory contains detailed reference documentation for the async-enumerable gem.
|
4
|
+
|
5
|
+
## Core Components
|
6
|
+
|
7
|
+
- [Async::Enumerable Module](enumerable.md) - Main module for adding async capabilities to enumerables
|
8
|
+
- [Async::Enumerator Class](enumerator.md) - Wrapper class providing async enumerable methods
|
9
|
+
- [ConcurrencyBounder Module](concurrency_bounder.md) - Bounded concurrency control
|
10
|
+
|
11
|
+
## Method Categories
|
12
|
+
|
13
|
+
### [Predicate Methods](methods/predicates.md)
|
14
|
+
- `all?`, `any?`, `none?`, `one?`
|
15
|
+
- `find`, `find_index`
|
16
|
+
- `include?`, `member?`
|
17
|
+
|
18
|
+
### [Transformer Methods](methods/transformers.md)
|
19
|
+
- `map`, `select`, `reject`
|
20
|
+
- `filter_map`, `flat_map`
|
21
|
+
- `compact`, `uniq`, `sort`, `sort_by`
|
22
|
+
|
23
|
+
### [Converter Methods](methods/converters.md)
|
24
|
+
- `to_a` - Convert to array
|
25
|
+
- `sync` - Materialize async chain results
|
26
|
+
|
27
|
+
## Quick Start
|
28
|
+
|
29
|
+
For basic usage, see the main [README](../../README.md). For detailed API documentation, explore the files linked above.
|
30
|
+
|
31
|
+
## Note on Documentation Style
|
32
|
+
|
33
|
+
The source code contains terse YARD documentation (2-3 lines) for quick reference. These detailed markdown files provide comprehensive documentation including:
|
34
|
+
|
35
|
+
- Detailed method descriptions
|
36
|
+
- Parameter explanations
|
37
|
+
- Return value documentation
|
38
|
+
- Usage examples
|
39
|
+
- Implementation notes
|
40
|
+
- Performance considerations
|
41
|
+
- Common patterns
|
42
|
+
|
43
|
+
This separation keeps the source code clean and readable while maintaining thorough documentation.
|