Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Warning Users that many parts of the utils module are deprecated and planned for removal #3

Open
Vizonex opened this issue Feb 27, 2025 · 1 comment

Comments

@Vizonex
Copy link
Owner

Vizonex commented Feb 27, 2025

@x42005e1f I was thinking about writing a subclass to label everything in the utils module as deprecated excluding the deprecated wrapper. This will warn users not to use the Lock and other things and to redirect users to use aiologic instead. I wanted your suggestions first before I make a new pull request with those changes first like we did last time since last time I think we did a very good job at brainstorming ideas.

@x42005e1f
Copy link
Collaborator

x42005e1f commented Feb 27, 2025

aiothreading can be characterized as:

  • asyncio-centric - it does not seek to support other libraries;
  • async-only - it aims at interaction of asynchronous tasks and omits the question of interaction with regular synchronous code.

I think on this basis it is better to redefine primitives in the utils module as asyncio-compatible but thread-aware (thread-safe). This is different from the aiologic approach, which solves a wider range of problems, but may be easier for users who expect acquire() instead of async_acquire() (aiologic style).

Here is an example of how Semaphore can be redefined via aiologic:

from types import TracebackType
from typing import Literal

import aiologic


class Semaphore:
    def __init__(self, value: int = 1) -> None:
        self.__impl = aiologic.Semaphore(value)

    async def __aenter__(self) -> None:
        await self.__impl.__aenter__()

        return None

    async def __aexit__(
        self,
        exc_type: type[BaseException] | None,
        exc: BaseException | None,
        tb: TracebackType | None,
    ) -> None:
        return await self.__impl.__aexit__(exc_type, exc, tb)

    async def acquire(self) -> Literal[True]:
        await self.__impl.async_acquire()

        return True

    def release(self, n: int = 1) -> None:
        self.__impl.async_release(n)

    def locked(self) -> bool:
        return self.__impl.waiting >= self._impl.value

The idea is to define asyncio-compatible interfaces, and write the implementation as a wrapper of an alternative from aiologic. And since "aiothreading" can be read as "threading for asyncio", it makes sense to add primitives (such as RLock) and features (such as support for n in Semaphore.release() as in the example above) that are not present in the asyncio module but are present in the threading module.

The interfaces can be taken from typeshed (asyncio, threading), and the semantics can be found in the standard library (asyncio, threading). As for wrapping, here is a mapping to the nearest alternatives from aiologic:

  • asyncio.Lock() -> aiologic.BoundedSemaphore(1)
  • threading.RLock() -> aiologic.RLock()
  • asyncio.Event() -> aiologic.Event()
  • asyncio.Condition() -> aiologic.Condition()
  • asyncio.Semaphore() -> aiologic.Semaphore()
  • asyncio.BoundedSemaphore() -> aiologic.BoundedSemaphore()
  • asyncio.Barrier() -> aiologic.RBarrier()

However, aiologic.RBarrier, which represents reusable barriers, is not yet implemented. Instead, we can use aiologic.Barrier, which represents cyclic barriers, but it does not support the reset() method.

The lack of primitives such as reusable barriers is due to the increased complexity of their implementation, which is set by the features of aiologic. In fact, I know the possible ways to implement them, and adding primitives like phase-fair RW locks is in my non-public TODO, but I have higher priorities right now.

At the moment, all recent updates are focused on improving existing functionality:

  • 0.15.0 (in development) - documenting, enriching the interfaces of some primitives (such as aiologic.RLock), and adding some helpful functions (such as aiologic.synchronized() as an async-aware alternative to wrapt.synchronized(), and aiologic.checkpoints() for more convenient checkpoint tuning)
  • 0.14.0 - improved support for libraries and interactive scenarios
  • 0.13.0 - added support for typing
  • ...

In the future, I also plan to extend the culsans derived library by adding there alternative implementations of primitives with API-compatible interfaces. For example, Semaphore(n) with O(1) memory (in aiologic it has O(n) memory due to lock-free implementation). When that point comes, primitives in aiothreading can be redefined via culsans.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants