Skip to content

Commit

Permalink
Add description for each concurrency method
Browse files Browse the repository at this point in the history
  • Loading branch information
ohbarye committed Apr 14, 2024
1 parent 9a15f21 commit 1262335
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 20 deletions.
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ Pbt.assert(num_runs: 100, seed: 42) do
end
```

## Concurrent methods
## Concurrency methods

One of the key features of `Pbt` is its ability to rapidly execute test cases in parallel or concurrently, using a large number of values (by default, `100`) generated by `Arbitrary`.

Expand All @@ -184,6 +184,8 @@ Be aware that the performance of each method depends on the test subject. For ex

### Ractor

`:ractor` worker is useful for test cases that are CPU-bound. But it's experimental and has some limitations as described below. If you encounter any issues due to those limitations, consider using `:process` as workers whose benchmark is the most similar to `:ractor`.
```ruby
Pbt.assert(worker: :ractor) do
Pbt.property(Pbt.integer) do |n|
Expand Down Expand Up @@ -224,6 +226,8 @@ end

### Process

If you'd like to run test cases that are CPU-bound and `:ractor` is not available, `:process` becomes a good choice.
```ruby
Pbt.assert(worker: :process) do
Pbt.property(Pbt.integer) do |n|
Expand All @@ -234,6 +238,8 @@ end
### Thread
You may not need to run test cases with multi-threads.
```ruby
Pbt.assert(worker: :thread) do
Pbt.property(Pbt.integer) do |n|
Expand All @@ -244,6 +250,8 @@ end
### None
For most cases, `:none` is the best choice. It runs tests sequentially (without parallelism) but most test cases finishes within a reasonable time.
```ruby
Pbt.assert(worker: :none) do
Pbt.property(Pbt.integer) do |n|
Expand Down
38 changes: 19 additions & 19 deletions lib/pbt/check/runner_methods.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,19 +75,36 @@ def run_it(property, source_values, config)
runner = Check::RunnerIterator.new(source_values, property, config[:verbose])
while runner.has_next?
case config[:worker]
in :none
run_it_in_sequential(property, runner)
in :ractor
run_it_in_ractors(property, runner)
in :process
run_it_in_processes(property, runner)
in :thread
run_it_in_threads(property, runner)
in :none
run_it_in_sequential(property, runner)
end
end
runner.run_execution
end

# @param property [Proc]
# @param runner [RunnerIterator]
# @return [void]
def run_it_in_sequential(property, runner)
runner.each_with_index do |val, index|
c = Case.new(val:, index:)
begin
property.run(val)
runner.handle_result(c)
rescue => e
c.exception = e
runner.handle_result(c)
break # Ignore the rest of the cases. Just pick up the first failure.
end
end
end

# @param property [Proc]
# @param runner [RunnerIterator]
# @return [void]
Expand Down Expand Up @@ -146,23 +163,6 @@ def run_it_in_processes(property, runner)
end
end

# @param property [Proc]
# @param runner [RunnerIterator]
# @return [void]
def run_it_in_sequential(property, runner)
runner.each_with_index do |val, index|
c = Case.new(val:, index:)
begin
property.run(val)
runner.handle_result(c)
rescue => e
c.exception = e
runner.handle_result(c)
break # Ignore the rest of the cases. Just pick up the first failure.
end
end
end

# Load Parallel gem. If it's not installed, raise an error.
# @see https://github.com/grosser/parallel
# @raise [InvalidConfiguration]
Expand Down

0 comments on commit 1262335

Please sign in to comment.