8000 Use only a single global lock for multiproc. (#167) · yeahnoob/client_python@cc852a9 · GitHub
[go: up one dir, main page]

Skip to content

Commit cc852a9

Browse files
authored
Use only a single global lock for multiproc. (prometheus#167)
This cuts ~350ns off the time for an operation, bringing it to ~1700ns. In multi process mode it's a reasonable assumption that there isn't any threading going on, so a single lock is faster than more granular locks.
1 parent 831023e commit cc852a9

File tree

1 file changed

+15
-13
lines changed

1 file changed

+15
-13
lines changed

prometheus_client/core.py

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,7 @@ def get(self):
309309
with self._lock:
310310
return self._value
311311

312+
312313
class _MmapedDict(object):
313314
"""A dict of doubles, backed by an mmapped file.
314315
@@ -317,9 +318,10 @@ class _MmapedDict(object):
317318
There's then a number of entries, consisting of a 4 byte int which is the
318319
size of the next field, a utf-8 encoded string key, padding to a 8 byte
319320
alignment, and then a 8 byte float which is the value.
321+
322+
Not thread safe.
320323
"""
321324
def __init__(self, filename):
322-
self._lock = Lock()
323325
self._f = open(filename, 'a+b')
324326
if os.fstat(self._f.fileno()).st_size == 0:
325327
self._f.truncate(_INITIAL_MMAP_SIZE)
@@ -371,17 +373,15 @@ def read_all_values(self):
371373
yield k, v
372374

373375
def read_value(self, key):
374-
with self._lock:
375-
if key not in self._positions:
376-
self._init_value(key)
376+
if key not in self._positions:
377+
self._init_value(key)
377378
pos = self._positions[key]
378379
# We assume that reading from an 8 byte aligned value is atomic
379380
return struct.unpack_from(b'd', self._m, pos)[0]
380381

381382
def write_value(self, key, value):
382-
with self._lock:
383-
if key not in self._positions:
384-
self._init_value(key)
383+
if key not in self._positions:
384+
self._init_value(key)
385385
pos = self._positions[key]
386386
# We assume that writing to an 8 byte aligned value is atomic
387387
struct.pack_into(b'd', self._m, pos, value)
@@ -395,7 +395,10 @@ def close(self):
395395
def _MultiProcessValue(__pid=os.getpid()):
396396
pid = __pid
397397
files = {}
398-
files_lock = Lock()
398+
# Use a single global lock when in multi-processing mode
399+
# as we presume this means there is no threading going on.
400+
# This avoids the need to also have mutexes in __MmapDict.
401+
lock = Lock()
399402

400403
class _MmapedValue(object):
401404
'''A float protected by a mutex backed by a per-process mmaped file.'''
@@ -407,28 +410,27 @@ def __init__(self, typ, metric_name, name, labelnames, labelvalues, multiprocess
407410
file_prefix = typ + '_' + multiprocess_mode
408411
else:
409412
file_prefix = typ
410-
with files_lock:
413+
with lock:
411414
if file_prefix not in files:
412415
filename = os.path.join(
413416
os.environ['prometheus_multiproc_dir'], '{0}_{1}.db'.format(file_prefix, pid))
414417
files[file_prefix] = _MmapedDict(filename)
415418
self._file = files[file_prefix]
416419
self._key = json.dumps((metric_name, name, labelnames, labelvalues))
417420
self._value = self._file.read_value(self._key)
418-
self._lock = Lock()
419421

420422
def inc(self, amount):
421-
with self._lock:
423+
with lock:
422424
self._value += amount
423425
self._file.write_value(self._key, self._value)
424426

425427
def set(self, value):
426-
with self._lock:
428+
with lock:
427429
self._value = value
428430
self._file.write_value(self._key, self._value)
429431

430432
def get(self):
431-
with self._lock:
433+
with lock:
432434
return self._value
433435

434436
return _MmapedValue

0 commit comments

Comments
 (0)
0