Last active
August 29, 2015 14:22
-
-
Save jsborjesson/6588f8ed0ad839d2ea1e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # This is a place where you can put code that should be executed once, | |
| # and accessed by several different threads. When it is called, it will | |
| # block the thread until the calculation has been completed, and memoize it. | |
| # | |
| # This means all threads that call the same method will wait for the same result, | |
| # that is only carried out once. Think of it as a traffic light; cars arrive at the | |
| # red light at different times, wait, and all take off together once it turns green. | |
| class CrossThreadMemoizer | |
| def initialize(callable) | |
| @callable = callable | |
| @lock = Mutex.new | |
| @cv = ConditionVariable.new | |
| end | |
| def call | |
| @lock.synchronize do | |
| fetch_resource unless resource_called? | |
| @cv.wait(@lock) unless resource_ready? | |
| @resource | |
| end | |
| end | |
| private | |
| def fetch_resource | |
| @resource_called = true | |
| @resource = @callable.call | |
| @cv.broadcast | |
| end | |
| def resource_called? | |
| !!@resource_called | |
| end | |
| def resource_ready? | |
| [email protected]? | |
| end | |
| end | |
| RSpec.describe CrossThreadMemoizer do | |
| it "calculates the result once and returns it for any thread requesting it" do | |
| num_threads = 5 | |
| result = double | |
| resource = double | |
| subject = described_class.new(resource) | |
| allow(resource).to receive(:call) { sleep 0.1; result } | |
| results = [] | |
| threads = num_threads.times.map { | |
| Thread.new do | |
| results << subject.call | |
| end | |
| } | |
| threads.each(&:join) | |
| expect(results).to eq [result] * num_threads | |
| expect(resource).to have_received(:call).once | |
| end | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment