A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Cancellation.html below:

Class: Concurrent::Cancellation — Concurrent Ruby

Note:

Edge Features are under active development and may change frequently.

The Cancellation abstraction provides cooperative cancellation.

The standard methods Thread#raise of Thread#kill available in Ruby are very dangerous (see linked the blog posts bellow). Therefore concurrent-ruby provides an alternative.

It provides an object which represents a task which can be executed, the task has to get the reference to the object and periodically cooperatively check that it is not cancelled. Good practices to make tasks cancellable:

The idea was inspired by https://msdn.microsoft.com/en-us/library/dd537607(v=vs.110).aspx

Examples

Run async task until cancelled

Create cancellation and then run work in a background thread until it is cancelled.

cancellation, origin = Concurrent::Cancellation.new
async_task = Concurrent::Promises.future(cancellation) do |cancellation|
    do_stuff until cancellation.canceled?
  :stopped_gracefully
end

sleep 0.01                               origin.resolve 
async_task.value!                        

Or let it raise an error.

cancellation, origin = Concurrent::Cancellation.new
async_task = Concurrent::Promises.future(cancellation) do |cancellation|
    while true
    cancellation.check!     
    do_stuff 
  end
end

sleep 0.01                               origin.resolve 
async_task.result

Run additional tasks on Cancellation

Cancellation can also be used to log or plan re-execution.

cancellation.origin.chain do
    end

Run only for limited time – Timeout replacement

Execute task for a given time then finish. Instead of letting Cancellation crate its own origin, it can be passed in as argument. The passed in origin is scheduled to be resolved in given time which then cancels the Cancellation.

timeout = Concurrent::Cancellation.new Concurrent::Promises.schedule(0.02)
timeout = Concurrent::Cancellation.timeout 0.02 
count   = Concurrent::AtomicFixnum.new
Concurrent.global_io_executor.post(timeout) do |timeout|
    count.increment until timeout.canceled?
end 

timeout.origin.wait
count.value                              

Parallel background processing with single cancellation

Each task tries to count to 1000 but there is a randomly failing test. The tasks share single cancellation, when one of them fails it cancels the others. The failing tasks ends with an error, the other tasks are gracefully cancelled.

cancellation, origin = Concurrent::Cancellation.new
tasks = 4.times.map do |i|
  Concurrent::Promises.future(cancellation, origin, i) do |cancellation, origin, i|
    count = 0
    100.times do
      break count = :cancelled if cancellation.canceled?
      count += 1
      sleep 0.001
      if rand > 0.95
        origin.resolve         raise 'random error'
      end
      count
    end
  end
end
Concurrent::Promises.zip(*tasks).result 

Without the randomly failing part it produces following.

cancellation, origin = Concurrent::Cancellation.new
tasks = 4.times.map do |i|
  Concurrent::Promises.future(cancellation, origin, i) do |cancellation, origin, i|
    count = 0
    100.times do
      break count = :cancelled if cancellation.canceled?
      count += 1
      sleep 0.001
                              count
    end
  end
end
Concurrent::Promises.zip(*tasks).result

Combine cancellations

The combination created by joining two cancellations cancels when the first or the other does.

cancellation_a, origin_a = Concurrent::Cancellation.new
cancellation_b, origin_b = Concurrent::Cancellation.new
combined_cancellation    = cancellation_a.join(cancellation_b)

origin_a.resolve

cancellation_a.canceled?                 cancellation_b.canceled?                 combined_cancellation.canceled?          

If a different rule for joining is needed, the source can be combined manually. The manually created cancellation cancels when both the first and the other cancels.

cancellation_a, origin_a = Concurrent::Cancellation.new
cancellation_b, origin_b = Concurrent::Cancellation.new
combined_cancellation    = Concurrent::Cancellation.new origin_a & origin_b

origin_a.resolve

cancellation_a.canceled?        cancellation_b.canceled?        combined_cancellation.canceled? 
origin_b.resolve
combined_cancellation.canceled? 
Instance Method Details #canceled? ⇒ true, false

Is the cancellation cancelled? Respective, was the origin of the cancellation resolved.

77
78
79
# File 'lib/concurrent-ruby-edge/concurrent/edge/cancellation.rb', line 77

def canceled?
  @Origin.resolved?
end
#check!(error = CancelledOperationError) ⇒ self

Raise error when cancelled

85
86
87
88
# File 'lib/concurrent-ruby-edge/concurrent/edge/cancellation.rb', line 85

def check!(error = CancelledOperationError)
  raise error if canceled?
  self
end
#join(*cancellations) ⇒ Cancellation

Creates a new Cancellation which is cancelled when first of the supplied cancellations or self is cancelled.

95
96
97
# File 'lib/concurrent-ruby-edge/concurrent/edge/cancellation.rb', line 95

def join(*cancellations)
  Cancellation.new Promises.any_event(*[@Origin, *cancellations.map(&:origin)])
end
#originPromises::Future, Promises::Event

The event or future which is the origin of the cancellation

70
71
72
# File 'lib/concurrent-ruby-edge/concurrent/edge/cancellation.rb', line 70

def origin
  @Origin
end
#to_s ⇒ String Also known as: inspect

Short string representation.

101
102
103
# File 'lib/concurrent-ruby-edge/concurrent/edge/cancellation.rb', line 101

def to_s
  format '%s %s>', super[0..-2], canceled? ? 'canceled' : 'pending'
end

RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4