Skip to main content

singleflight

Build Status

Coalesce multiple identical call into one, preventing thundering-herd/stampede to database/other backends

It is a python port of golang's groupcache singleflight implementation

This module does not provide caching mechanism. Rather, this module can used behind a caching abstraction to deduplicate cache-filling call

Only support python 3.5+

Installation

pip install singleflight

Usage

This modules has 3 implementation, which can be imported as follows

from singleflight.basic import SingleFlight # for multi-threaded apps
from singleflight.gevent import SingleFlightGevent as SingleFlight # for gevent apps
from singleflight.asynchronous import SingleFlightAsync as SingleFlight # for asyncio/curio apps

Then you can use it as follows (the example shows the multi-threaded version). Note that, key is important for the modules to know which call should be de-duplicated

from time import sleep
from concurrent.futures import ThreadPoolExecutor
from functools import partial

from singleflight.basic import SingleFlight

if __name__ == '__main__':
  sf = SingleFlight()
  executor = ThreadPoolExecutor(max_workers=10)

  counter = 0
  result = "this is the result"
  def work(num):
    global counter, result
    sleep(0.1) # emulate bit slower call
    counter += 1
    return (result, num)

  res = []
  for i in range(10):
    sfc = partial(sf.call, work, "key", i+1)
    r = executor.submit(sfc)
    res.append(r)

  for r in res:
    assert r.result()[0] == result
    # because only the first one can get the lock
    # and only that one request call
    assert r.result()[1] == 1
  
  assert counter == 1

For decorator fans, you can also use it to wrap your function.

from time import sleep
from concurrent.futures import ThreadPoolExecutor
from functools import partial

from singleflight.basic import SingleFlight

if __name__ == '__main__':
  sf = SingleFlight()
  executor = ThreadPoolExecutor(max_workers=10)

  # success case
  counter = 0
  result = "this is the result"

  @sf.wrap
  def work(num):
    global counter, result
    sleep(0.1) # emulate bit slower call
    counter += 1
    return (result, num)

  res = []
  for i in range(10):
    sfc = partial(work, "key", i+1)
    r = executor.submit(sfc)
    res.append(r)

  for r in res:
    assert r.result()[0] == result
    # because only the first one can get the lock
    # and only that one request call
    assert r.result()[1] == 1
  
  assert counter == 1

All *args and **kwargs your function has is passed directly later. Exceptions are also raised normally.

Metadata

Release files for singleflight 0.1.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for singleflight 0.1.3
File Size Uploaded
singleflight-0.1.3.tar.gz 4.1 kB Details

Release files / singleflight-0.1.3.tar.gz

Download URL singleflight-0.1.3.tar.gz
Size 4.1 kB
Tags Source
SHA-256 checksum
How to use checksums
411889f200804e5f19e9279d4b8d3213a1f44f35250a5e5eba6f1f3d16b7b524
BLAKE2b-256 checksum
How to use checksums
42b4aed8e832246f417105464939a71bb7d4d5547a56b53870b87d2a43ff1d24
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.1.1 pkginfo/1.5.0.1 requests/2.21.0 setuptools/49.1.0 requests-toolbelt/0.9.1 tqdm/4.46.0 CPython/3.7.3

Release history Release notifications | RSS feed

This release

0.1.3 This release

1 release file

0.1.2

1 release file

0.1.1

1 release file

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page