Skip to content

Document that cache() and lru_cache() do not have a "call once" guarantee #103475

Closed
@okrcma

Description

@okrcma

Documentation

The documentation for @functools.cache states that

The cache is threadsafe so the wrapped function can be used in multiple threads.

but it is not threadsafe before the value is cached.

In the following example the wrapped function will return two different instances of list.

import functools
from threading import Thread
from time import sleep


@functools.cache
def get_cached_object():
    sleep(1)  # stand-in for some logic which takes some time to execute
    return list()


def run():
    print(f"{id(get_cached_object())}\n")


if __name__ == "__main__":
    first_thread = Thread(target=run)
    second_thread = Thread(target=run)

    first_thread.start()
    second_thread.start()

    sleep(2)  # wait for both threads to finish
    run()

This is an issue, for example, when you use @functools.cache for implementation of singletons (we can leave debate about singletons not being a good practice out of this).

The documentation should not claim the cache to be threadsafe or there should be an explicit warning about this situation.

Linked PRs

Metadata

Metadata

Assignees

Labels

docsDocumentation in the Doc dir

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions