Class: Concurrent::Map

Inherits:
Collection::MapImplementation
  • Object
show all
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::Mapis 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

Constant Summary

Instance Method Summary (collapse)

Constructor Details

- (Map) initialize(options = nil, &block)

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(options = nil, &block)
  if options.kind_of?(::Hash)
    validate_options_hash!(options)
  else
    options = nil
  end

  super(options)
  @default_proc = block
end

Instance Method Details

- (undocumented) [](key) 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

- (undocumented) compute

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

- (undocumented) compute_if_absent

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

- (undocumented) compute_if_present

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

- (undocumented) delete

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

- (undocumented) delete_pair

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(options = nil, &block)
  if options.kind_of?(::Hash)
    validate_options_hash!(options)
  else
    options = nil
  end

  super(options)
  @default_proc = block
end

- (undocumented) each_key



166
167
168
# File 'lib/concurrent/map.rb', line 166

def each_key
  each_pair {|k, v| yield k}
end

- (undocumented) each_value



170
171
172
# File 'lib/concurrent/map.rb', line 170

def each_value
  each_pair {|k, v| yield v}
end

- (Boolean) empty?

Returns:

  • (Boolean)


182
183
184
185
# File 'lib/concurrent/map.rb', line 182

def empty?
  each_pair {|k, v| return false}
  true
end

- (undocumented) fetch(key, default_value = NULL)

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

- (undocumented) fetch_or_store(key, default_value = NULL)

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

- (undocumented) get_and_set

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

- (undocumented) inspect

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

- (undocumented) key(value) 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

- (undocumented) keys



154
155
156
157
158
# File 'lib/concurrent/map.rb', line 154

def keys
  arr = []
  each_pair {|k, v| arr << k}
  arr
end

- (undocumented) marshal_dump

Raises:

  • (TypeError)


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

- (undocumented) marshal_load(hash)



200
201
202
203
# File 'lib/concurrent/map.rb', line 200

def marshal_load(hash)
  initialize
  populate_from(hash)
end

- (undocumented) merge_pair

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

- (undocumented) put_if_absent(key, value)

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

- (undocumented) replace_if_exists

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

- (undocumented) replace_pair

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

- (undocumented) size



187
188
189
190
191
# File 'lib/concurrent/map.rb', line 187

def size
  count = 0
  each_pair {|k, v| count += 1}
  count
end

- (Boolean) value?(value)

Returns:

  • (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

- (undocumented) values



160
161
162
163
164
# File 'lib/concurrent/map.rb', line 160

def values
  arr = []
  each_pair {|k, v| arr << v}
  arr
end