Class: Concurrent::Map
- Inherits:
-
Collection::MapImplementation
- Object
- Concurrent::Map
- Defined in:
- lib/concurrent/map.rb
Overview
‘Concurrent::Map` is a hash-like object and should have much better performance characteristics, especially under high concurrency, than `Concurrent::Hash`. However, `Concurrent::Map `is not strictly semantically equivalent to a ruby `Hash` – for instance, it does not necessarily retain ordering by insertion time as `Hash` does. For most uses it should do fine though, and we recommend you consider `Concurrent::Map` instead of `Concurrent::Hash` for your concurrency-safe hash needs.
> require ‘concurrent’ > > map = Concurrent::Map.new
Instance Method Summary collapse
- #[](key) ⇒ Object (also: #get)
-
#compute ⇒ Object
This method is atomic.
-
#compute_if_absent ⇒ Object
This method is atomic.
-
#compute_if_present ⇒ Object
This method is atomic.
-
#delete ⇒ Object
This method is atomic.
-
#delete_pair ⇒ Object
This method is atomic.
- #each_key ⇒ Object
- #each_value ⇒ Object
- #empty? ⇒ Boolean
-
#fetch(key, default_value = NULL) ⇒ Object
The “fetch-then-act” methods of ‘Map` are not atomic.
-
#fetch_or_store(key, default_value = NULL) ⇒ Object
The “fetch-then-act” methods of ‘Map` are not atomic.
-
#get_and_set ⇒ Object
This method is atomic.
-
#initialize(options = nil, &block) ⇒ Map
constructor
A new instance of Map.
-
#inspect ⇒ Object
override default #inspect() method: firstly, we don’t want to be spilling our guts (i-vars), secondly, MRI backend’s #inspect() call on its @backend i-var will bump @backend’s iter level while possibly yielding GVL.
- #key(value) ⇒ Object (also: #index)
- #keys ⇒ Object
- #marshal_dump ⇒ Object
- #marshal_load(hash) ⇒ Object
-
#merge_pair ⇒ Object
This method is atomic.
-
#put_if_absent(key, value) ⇒ Object
This method is atomic.
-
#replace_if_exists ⇒ Object
This method is atomic.
-
#replace_pair ⇒ Object
This method is atomic.
- #size ⇒ Object
- #value?(value) ⇒ Boolean
- #values ⇒ Object
Constructor Details
#initialize(options = nil, &block) ⇒ Map
Returns a new instance of Map.
81 82 83 84 85 86 87 88 89 90 |
# File 'lib/concurrent/map.rb', line 81 def initialize( = nil, &block) if .kind_of?(::Hash) () else = nil end super() @default_proc = block end |
Instance Method Details
#[](key) ⇒ Object Also known as: get
92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/concurrent/map.rb', line 92 def [](key) if value = super # non-falsy value is an existing mapping, return it right away value # re-check is done with get_or_default(key, NULL) instead of a simple !key?(key) in order to avoid a race condition, whereby by the time the current thread gets to the key?(key) call # a key => value mapping might have already been created by a different thread (key?(key) would then return true, this elsif branch wouldn't be taken and an incorrent +nil+ value # would be returned) # note: nil == value check is not technically necessary elsif @default_proc && nil == value && NULL == (value = get_or_default(key, NULL)) @default_proc.call(self, key) else value end end |
#compute ⇒ Object
This method is atomic. Atomic methods of ‘Map` which accept a block do not allow the `self` instance to be used within the block. Doing so will cause a deadlock.
|
# File 'lib/concurrent/map.rb', line 60
|
#compute_if_absent ⇒ Object
This method is atomic. Atomic methods of ‘Map` which accept a block do not allow the `self` instance to be used within the block. Doing so will cause a deadlock.
|
# File 'lib/concurrent/map.rb', line 54
|
#compute_if_present ⇒ Object
This method is atomic. Atomic methods of ‘Map` which accept a block do not allow the `self` instance to be used within the block. Doing so will cause a deadlock.
|
# File 'lib/concurrent/map.rb', line 57
|
#delete ⇒ Object
This method is atomic. Atomic methods of ‘Map` which accept a block do not allow the `self` instance to be used within the block. Doing so will cause a deadlock.
|
# File 'lib/concurrent/map.rb', line 75
|
#delete_pair ⇒ Object
This method is atomic. Atomic methods of ‘Map` which accept a block do not allow the `self` instance to be used within the block. Doing so will cause a deadlock.
81 82 83 84 85 86 87 88 89 90 |
# File 'lib/concurrent/map.rb', line 81 def initialize( = nil, &block) if .kind_of?(::Hash) () else = nil end super() @default_proc = block end |
#each_key ⇒ Object
166 167 168 |
# File 'lib/concurrent/map.rb', line 166 def each_key each_pair {|k, v| yield k} end |
#each_value ⇒ Object
170 171 172 |
# File 'lib/concurrent/map.rb', line 170 def each_value each_pair {|k, v| yield v} end |
#empty? ⇒ Boolean
182 183 184 185 |
# File 'lib/concurrent/map.rb', line 182 def empty? each_pair {|k, v| return false} true end |
#fetch(key, default_value = NULL) ⇒ Object
The “fetch-then-act” methods of ‘Map` are not atomic. `Map` is intended to be use as a concurrency primitive with strong happens-before guarantees. It is not intended to be used as a high-level abstraction supporting complex operations. All read and write operations are thread safe, but no guarantees are made regarding race conditions between the fetch operation and yielding to the block. Additionally, this method does not support recursion. This is due to internal constraints that are very unlikely to change in the near future.
118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/concurrent/map.rb', line 118 def fetch(key, default_value = NULL) if NULL != (value = get_or_default(key, NULL)) value elsif block_given? yield key elsif NULL != default_value default_value else raise_fetch_no_key end end |
#fetch_or_store(key, default_value = NULL) ⇒ Object
The “fetch-then-act” methods of ‘Map` are not atomic. `Map` is intended to be use as a concurrency primitive with strong happens-before guarantees. It is not intended to be used as a high-level abstraction supporting complex operations. All read and write operations are thread safe, but no guarantees are made regarding race conditions between the fetch operation and yielding to the block. Additionally, this method does not support recursion. This is due to internal constraints that are very unlikely to change in the near future.
131 132 133 134 135 |
# File 'lib/concurrent/map.rb', line 131 def fetch_or_store(key, default_value = NULL) fetch(key) do put(key, block_given? ? yield(key) : (NULL == default_value ? raise_fetch_no_key : default_value)) end end |
#get_and_set ⇒ Object
This method is atomic. Atomic methods of ‘Map` which accept a block do not allow the `self` instance to be used within the block. Doing so will cause a deadlock.
|
# File 'lib/concurrent/map.rb', line 72
|
#inspect ⇒ Object
override default #inspect() method: firstly, we don’t want to be spilling our guts (i-vars), secondly, MRI backend’s #inspect() call on its @backend i-var will bump @backend’s iter level while possibly yielding GVL
211 212 213 214 |
# File 'lib/concurrent/map.rb', line 211 def inspect id_str = (object_id << 1).to_s(16).rjust(DEFAULT_OBJ_ID_STR_WIDTH, '0') "#<#{self.class.name}:0x#{id_str} entries=#{size} default_proc=#{@default_proc.inspect}>" end |
#key(value) ⇒ Object Also known as: index
176 177 178 179 |
# File 'lib/concurrent/map.rb', line 176 def key(value) each_pair {|k, v| return k if v == value} nil end |
#keys ⇒ Object
154 155 156 157 158 |
# File 'lib/concurrent/map.rb', line 154 def keys arr = [] each_pair {|k, v| arr << k} arr end |
#marshal_dump ⇒ Object
193 194 195 196 197 198 |
# File 'lib/concurrent/map.rb', line 193 def marshal_dump raise TypeError, "can't dump hash with default proc" if @default_proc h = {} each_pair {|k, v| h[k] = v} h end |
#marshal_load(hash) ⇒ Object
200 201 202 203 |
# File 'lib/concurrent/map.rb', line 200 def marshal_load(hash) initialize populate_from(hash) end |
#merge_pair ⇒ Object
This method is atomic. Atomic methods of ‘Map` which accept a block do not allow the `self` instance to be used within the block. Doing so will cause a deadlock.
|
# File 'lib/concurrent/map.rb', line 63
|
#put_if_absent(key, value) ⇒ Object
This method is atomic. Atomic methods of ‘Map` which accept a block do not allow the `self` instance to be used within the block. Doing so will cause a deadlock.
|
# File 'lib/concurrent/map.rb', line 51
|
#replace_if_exists ⇒ Object
This method is atomic. Atomic methods of ‘Map` which accept a block do not allow the `self` instance to be used within the block. Doing so will cause a deadlock.
|
# File 'lib/concurrent/map.rb', line 69
|
#replace_pair ⇒ Object
This method is atomic. Atomic methods of ‘Map` which accept a block do not allow the `self` instance to be used within the block. Doing so will cause a deadlock.
|
# File 'lib/concurrent/map.rb', line 66
|
#size ⇒ Object
187 188 189 190 191 |
# File 'lib/concurrent/map.rb', line 187 def size count = 0 each_pair {|k, v| count += 1} count end |
#value?(value) ⇒ Boolean
147 148 149 150 151 152 |
# File 'lib/concurrent/map.rb', line 147 def value?(value) each_value do |v| return true if value.equal?(v) end false end |
#values ⇒ Object
160 161 162 163 164 |
# File 'lib/concurrent/map.rb', line 160 def values arr = [] each_pair {|k, v| arr << v} arr end |