rwlocker 3.2__tar.gz → 3.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {rwlocker-3.2/rwlocker.egg-info → rwlocker-3.3}/PKG-INFO +13 -12
- {rwlocker-3.2 → rwlocker-3.3}/README-pypi.md +12 -11
- {rwlocker-3.2 → rwlocker-3.3}/pyproject.toml +1 -1
- {rwlocker-3.2 → rwlocker-3.3}/rwlocker/__init__.py +8 -8
- {rwlocker-3.2 → rwlocker-3.3}/rwlocker/async_rwlock.py +251 -653
- rwlocker-3.3/rwlocker/base.py +331 -0
- rwlocker-3.3/rwlocker/mixins.py +451 -0
- rwlocker-3.3/rwlocker/queues.py +200 -0
- {rwlocker-3.2 → rwlocker-3.3}/rwlocker/thread_rwlock.py +259 -677
- {rwlocker-3.2 → rwlocker-3.3/rwlocker.egg-info}/PKG-INFO +13 -12
- {rwlocker-3.2 → rwlocker-3.3}/rwlocker.egg-info/SOURCES.txt +3 -0
- {rwlocker-3.2 → rwlocker-3.3}/LICENSE +0 -0
- {rwlocker-3.2 → rwlocker-3.3}/MANIFEST.in +0 -0
- {rwlocker-3.2 → rwlocker-3.3}/rwlocker.egg-info/dependency_links.txt +0 -0
- {rwlocker-3.2 → rwlocker-3.3}/rwlocker.egg-info/top_level.txt +0 -0
- {rwlocker-3.2 → rwlocker-3.3}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rwlocker
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.3
|
|
4
4
|
Summary: Advanced, High-Performance, and State-Machine Based Synchronous/Asynchronous Read-Write Locks.
|
|
5
5
|
Author-email: TahsinCr <TahsinCrs@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -71,13 +71,13 @@ Standard `Condition` structures in the library wake up all waiting threads/tasks
|
|
|
71
71
|
* **Smart Proxy Architecture:** Intuitive usage of `with` and `async with` context managers via `.read` and `.write` proxies.
|
|
72
72
|
* **Atomic Downgrading:** The ability to instantly downgrade a Write lock to a Read lock (`downgrade()`) without completely releasing the lock, preventing other writers from slipping in.
|
|
73
73
|
* **Safe Reentrancy:** O(1) memory pointer tracking allowing the same thread or task to repeatedly acquire a write lock without causing a Deadlock.
|
|
74
|
-
* **
|
|
75
|
-
* **
|
|
76
|
-
* **
|
|
77
|
-
* **
|
|
78
|
-
* **
|
|
79
|
-
*
|
|
80
|
-
*
|
|
74
|
+
* **Pure O(1) Condition Variables:** Unlike standard `Condition` structures, it does not iterate through the waiting list one by one during `notify_all()` calls (bypassing O(N) scanning costs). Thanks to its customized C-level micro-queue architecture, it wakes up thousands of tasks instantly without causing a "Cache Stampede" and choking the CPU.
|
|
75
|
+
* **Asynchronous Cancellation Safety & Shielding:** Full resilience against task cancellations (`CancelledError`) in the `asyncio` environment. If a task is cancelled while waiting for a lock or inside `Condition.wait()`, the system state is never corrupted. The lock is safely recovered, no "zombie" waiters are left behind, and wait queues remain perfectly clean.
|
|
76
|
+
* **100% Drop-in Replacement:** You can inject your advanced locks (`RWLockFair`, etc.) and conditions (`RWCondition`, etc.) directly into third-party libraries (SQLAlchemy, requests, FastAPI, etc.) expecting standard `threading.Lock`, `asyncio.Lock`, `threading.Condition`, or `asyncio.Condition` instances without making any code changes. Standard API calls (e.g., `lock.acquire()`, `cond.wait()`) are automatically and safely routed to the `.write` (exclusive) proxy.
|
|
77
|
+
* **"Happy Path" Performance Isolation:** A next-generation architecture that completely bypasses O(N) cost garbage cleanup operations upon successful lock and queue wake-ups. It provides absolute protection against OS-Interrupts and timeouts while completing successful wake-ups with zero CPU overhead.
|
|
78
|
+
* **Standard Adapters:** Includes standard wrappers for Dependency Injection workflows where you want to maintain the exact same architectural signature (`.read` and `.write`) but do not require advanced lock strategies.
|
|
79
|
+
* *Lock Adapters:* `Lock` (Thread), `AsyncLock` (Asyncio)
|
|
80
|
+
* *Condition Adapters:* `Condition` (Thread), `AsyncCondition` (Asyncio)
|
|
81
81
|
|
|
82
82
|
### 🛡️ Lock Strategies
|
|
83
83
|
|
|
@@ -87,7 +87,8 @@ You can select the right lock strategy based on your system's bottleneck profile
|
|
|
87
87
|
| --- | --- | --- | --- |
|
|
88
88
|
| **Writer-Preferring** | `RWLockWrite` / `AsyncRWLockWrite` | Forbids new readers from entering if there is a waiting writer. Prevents writer starvation. | To prevent writers from being overwhelmed in read-heavy systems. |
|
|
89
89
|
| **Reader-Preferring** | `RWLockRead` / `AsyncRWLockRead` | Continuously allows new readers in, even if writers are waiting. Provides maximum parallelism. | In cache structures where write operations are very rare or non-critical. |
|
|
90
|
-
| **Fair** | `
|
|
90
|
+
| **Reader-Phase Fair** | `RWLockReaderPhaseFair` / `AsyncRWLockReaderPhaseFair` | Alternates between reader and writer phases, but late readers may still join an already-open reader phase for higher read throughput. | When you want bounded fairness without fully freezing each reader batch. |
|
|
91
|
+
| **Fair** | `RWLockFair` / `AsyncRWLockFair` | Freezes each reader phase at phase start so late readers cannot cut in front of an already-queued writer. Prevents starvation for both sides with stricter ordering. | In high-frequency, bidirectional traffic (MAVLink, WebSockets, etc.) where deterministic writer latency matters. |
|
|
91
92
|
> 💡 **Condition Compatibility:** The `RWCondition` and `AsyncRWCondition` classes in the library are designed to encapsulate all the lock strategies mentioned above (Dependency Injection). You can choose the lock that best fits your system and transform it into a state machine running at pure O(1) speed.
|
|
92
93
|
<br/>
|
|
93
94
|
|
|
@@ -116,7 +117,7 @@ The performance results demonstrate `rwlocker`'s true potential during Network a
|
|
|
116
117
|
|
|
117
118
|
**🖥️ Test Environment:** All tests were executed on an **Intel Core i7-12700H (2.4GHz)** processor running **EndeavourOS (Arch-based Linux)**, using **Python 3.14.3** and the experimental **Free-Threading (3.14.3t)** interpreters.
|
|
118
119
|
|
|
119
|
-
**🧪 Methodology:** To ensure absolute precision and zero margin of error, all reader and writer entities (threads or async tasks) are spawned in advance and held at a starting line using a synchronization `Event`. Once the event triggers, they execute simultaneously. The workloads strictly follow an `IOBoundScenario` that enforces a precise `time.sleep(0.001)` or `asyncio.sleep(0.001)` delay to accurately simulate real network/database I/O latency.
|
|
120
|
+
**🧪 Methodology:** To ensure absolute precision and zero margin of error, all reader and writer entities (threads or async tasks) are spawned in advance and held at a starting line using a synchronization `Event`. Once the event triggers, they execute simultaneously. The workloads strictly follow an `IOBoundScenario` that enforces a precise `time.sleep(0.001)` or `asyncio.sleep(0.001)` delay across 10 consecutive iterations to accurately simulate real network/database I/O latency.
|
|
120
121
|
|
|
121
122
|
### 1. Read-Write Lock (RWLock) Benchmarks
|
|
122
123
|
|
|
@@ -133,12 +134,12 @@ In the Read-Heavy scenario, standard C-based locks choke the system, whereas `rw
|
|
|
133
134
|
Standard `Condition` variables iterate through all sleeping threads/tasks one by one `O(N)` during a broadcast (`notify_all`), causing massive CPU spikes and "Cache Stampedes". `rwlocker` completely eradicates this with its pure `O(1)` queueing architecture.
|
|
134
135
|
|
|
135
136
|
**Synchronous (Thread) RWCondition Performance:**
|
|
136
|
-
When 100 sleeping readers are awakened simultaneously, `rwlocker` processes them instantly without locking the OS. This architectural leap results in a
|
|
137
|
+
When 100 sleeping readers are awakened simultaneously, `rwlocker` processes them instantly without locking the OS. This architectural leap results in a **~45x speedup** compared to the standard library's `threading.Condition`.
|
|
137
138
|
|
|
138
139
|
**Asynchronous (Asyncio) RWCondition Performance:**
|
|
139
140
|
In event-driven caching systems, waking up hundreds of waiting web requests simultaneously is a major bottleneck. The `AsyncRWCondition` completely bypasses standard asyncio constraints, reaching up to **~45x higher throughput** during massive broadcast scenarios, completely saving the loop from freezing.
|
|
140
141
|
|
|
141
|
-
*(Note: All lock, adapter, and condition classes have passed a massive suite of **
|
|
142
|
+
*(Note: All lock, adapter, and condition classes have passed a massive suite of **412 different unit tests** covering reentrancy, deadlock, timeout, OS interrupts, O(N) leaks, and cancellation safety scenarios with 0 errors, and this entire test suite was completed in just **15.7 seconds**.)*
|
|
142
143
|
|
|
143
144
|
|
|
144
145
|
<br/>
|
|
@@ -42,13 +42,13 @@ Standard `Condition` structures in the library wake up all waiting threads/tasks
|
|
|
42
42
|
* **Smart Proxy Architecture:** Intuitive usage of `with` and `async with` context managers via `.read` and `.write` proxies.
|
|
43
43
|
* **Atomic Downgrading:** The ability to instantly downgrade a Write lock to a Read lock (`downgrade()`) without completely releasing the lock, preventing other writers from slipping in.
|
|
44
44
|
* **Safe Reentrancy:** O(1) memory pointer tracking allowing the same thread or task to repeatedly acquire a write lock without causing a Deadlock.
|
|
45
|
-
* **
|
|
46
|
-
* **
|
|
47
|
-
* **
|
|
48
|
-
* **
|
|
49
|
-
* **
|
|
50
|
-
*
|
|
51
|
-
*
|
|
45
|
+
* **Pure O(1) Condition Variables:** Unlike standard `Condition` structures, it does not iterate through the waiting list one by one during `notify_all()` calls (bypassing O(N) scanning costs). Thanks to its customized C-level micro-queue architecture, it wakes up thousands of tasks instantly without causing a "Cache Stampede" and choking the CPU.
|
|
46
|
+
* **Asynchronous Cancellation Safety & Shielding:** Full resilience against task cancellations (`CancelledError`) in the `asyncio` environment. If a task is cancelled while waiting for a lock or inside `Condition.wait()`, the system state is never corrupted. The lock is safely recovered, no "zombie" waiters are left behind, and wait queues remain perfectly clean.
|
|
47
|
+
* **100% Drop-in Replacement:** You can inject your advanced locks (`RWLockFair`, etc.) and conditions (`RWCondition`, etc.) directly into third-party libraries (SQLAlchemy, requests, FastAPI, etc.) expecting standard `threading.Lock`, `asyncio.Lock`, `threading.Condition`, or `asyncio.Condition` instances without making any code changes. Standard API calls (e.g., `lock.acquire()`, `cond.wait()`) are automatically and safely routed to the `.write` (exclusive) proxy.
|
|
48
|
+
* **"Happy Path" Performance Isolation:** A next-generation architecture that completely bypasses O(N) cost garbage cleanup operations upon successful lock and queue wake-ups. It provides absolute protection against OS-Interrupts and timeouts while completing successful wake-ups with zero CPU overhead.
|
|
49
|
+
* **Standard Adapters:** Includes standard wrappers for Dependency Injection workflows where you want to maintain the exact same architectural signature (`.read` and `.write`) but do not require advanced lock strategies.
|
|
50
|
+
* *Lock Adapters:* `Lock` (Thread), `AsyncLock` (Asyncio)
|
|
51
|
+
* *Condition Adapters:* `Condition` (Thread), `AsyncCondition` (Asyncio)
|
|
52
52
|
|
|
53
53
|
### 🛡️ Lock Strategies
|
|
54
54
|
|
|
@@ -58,7 +58,8 @@ You can select the right lock strategy based on your system's bottleneck profile
|
|
|
58
58
|
| --- | --- | --- | --- |
|
|
59
59
|
| **Writer-Preferring** | `RWLockWrite` / `AsyncRWLockWrite` | Forbids new readers from entering if there is a waiting writer. Prevents writer starvation. | To prevent writers from being overwhelmed in read-heavy systems. |
|
|
60
60
|
| **Reader-Preferring** | `RWLockRead` / `AsyncRWLockRead` | Continuously allows new readers in, even if writers are waiting. Provides maximum parallelism. | In cache structures where write operations are very rare or non-critical. |
|
|
61
|
-
| **Fair** | `
|
|
61
|
+
| **Reader-Phase Fair** | `RWLockReaderPhaseFair` / `AsyncRWLockReaderPhaseFair` | Alternates between reader and writer phases, but late readers may still join an already-open reader phase for higher read throughput. | When you want bounded fairness without fully freezing each reader batch. |
|
|
62
|
+
| **Fair** | `RWLockFair` / `AsyncRWLockFair` | Freezes each reader phase at phase start so late readers cannot cut in front of an already-queued writer. Prevents starvation for both sides with stricter ordering. | In high-frequency, bidirectional traffic (MAVLink, WebSockets, etc.) where deterministic writer latency matters. |
|
|
62
63
|
> 💡 **Condition Compatibility:** The `RWCondition` and `AsyncRWCondition` classes in the library are designed to encapsulate all the lock strategies mentioned above (Dependency Injection). You can choose the lock that best fits your system and transform it into a state machine running at pure O(1) speed.
|
|
63
64
|
<br/>
|
|
64
65
|
|
|
@@ -87,7 +88,7 @@ The performance results demonstrate `rwlocker`'s true potential during Network a
|
|
|
87
88
|
|
|
88
89
|
**🖥️ Test Environment:** All tests were executed on an **Intel Core i7-12700H (2.4GHz)** processor running **EndeavourOS (Arch-based Linux)**, using **Python 3.14.3** and the experimental **Free-Threading (3.14.3t)** interpreters.
|
|
89
90
|
|
|
90
|
-
**🧪 Methodology:** To ensure absolute precision and zero margin of error, all reader and writer entities (threads or async tasks) are spawned in advance and held at a starting line using a synchronization `Event`. Once the event triggers, they execute simultaneously. The workloads strictly follow an `IOBoundScenario` that enforces a precise `time.sleep(0.001)` or `asyncio.sleep(0.001)` delay to accurately simulate real network/database I/O latency.
|
|
91
|
+
**🧪 Methodology:** To ensure absolute precision and zero margin of error, all reader and writer entities (threads or async tasks) are spawned in advance and held at a starting line using a synchronization `Event`. Once the event triggers, they execute simultaneously. The workloads strictly follow an `IOBoundScenario` that enforces a precise `time.sleep(0.001)` or `asyncio.sleep(0.001)` delay across 10 consecutive iterations to accurately simulate real network/database I/O latency.
|
|
91
92
|
|
|
92
93
|
### 1. Read-Write Lock (RWLock) Benchmarks
|
|
93
94
|
|
|
@@ -104,12 +105,12 @@ In the Read-Heavy scenario, standard C-based locks choke the system, whereas `rw
|
|
|
104
105
|
Standard `Condition` variables iterate through all sleeping threads/tasks one by one `O(N)` during a broadcast (`notify_all`), causing massive CPU spikes and "Cache Stampedes". `rwlocker` completely eradicates this with its pure `O(1)` queueing architecture.
|
|
105
106
|
|
|
106
107
|
**Synchronous (Thread) RWCondition Performance:**
|
|
107
|
-
When 100 sleeping readers are awakened simultaneously, `rwlocker` processes them instantly without locking the OS. This architectural leap results in a
|
|
108
|
+
When 100 sleeping readers are awakened simultaneously, `rwlocker` processes them instantly without locking the OS. This architectural leap results in a **~45x speedup** compared to the standard library's `threading.Condition`.
|
|
108
109
|
|
|
109
110
|
**Asynchronous (Asyncio) RWCondition Performance:**
|
|
110
111
|
In event-driven caching systems, waking up hundreds of waiting web requests simultaneously is a major bottleneck. The `AsyncRWCondition` completely bypasses standard asyncio constraints, reaching up to **~45x higher throughput** during massive broadcast scenarios, completely saving the loop from freezing.
|
|
111
112
|
|
|
112
|
-
*(Note: All lock, adapter, and condition classes have passed a massive suite of **
|
|
113
|
+
*(Note: All lock, adapter, and condition classes have passed a massive suite of **412 different unit tests** covering reentrancy, deadlock, timeout, OS interrupts, O(N) leaks, and cancellation safety scenarios with 0 errors, and this entire test suite was completed in just **15.7 seconds**.)*
|
|
113
114
|
|
|
114
115
|
|
|
115
116
|
<br/>
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "rwlocker"
|
|
7
|
-
version = "3.
|
|
7
|
+
version = "3.3"
|
|
8
8
|
description = "Advanced, High-Performance, and State-Machine Based Synchronous/Asynchronous Read-Write Locks."
|
|
9
9
|
readme = {file = "README-pypi.md", content-type = "text/markdown"}
|
|
10
10
|
license = {text = "MIT"}
|
|
@@ -10,9 +10,9 @@ it guarantees strict data safety while maximizing read concurrency and
|
|
|
10
10
|
preventing CPU/Event-Loop bottlenecks.
|
|
11
11
|
|
|
12
12
|
Key Architectural Features:
|
|
13
|
-
- **Multiple Scheduling Strategies**: Choose between Write-preferring,
|
|
14
|
-
Read-preferring, and Fair
|
|
15
|
-
on your specific workload.
|
|
13
|
+
- **Multiple Scheduling Strategies**: Choose between Write-preferring,
|
|
14
|
+
Read-preferring, Reader-Phase Fair, and Strict Fair algorithms to prevent
|
|
15
|
+
starvation based on your specific workload.
|
|
16
16
|
- **O(1) Condition Queuing (Stampede Protection)**: Condition variables
|
|
17
17
|
(`RWCondition`, `AsyncRWCondition`) utilize pure O(1) waiter queues
|
|
18
18
|
to completely eliminate O(N) cache stampedes and event-loop blocking
|
|
@@ -36,15 +36,15 @@ Important Usage Notes & Gotchas:
|
|
|
36
36
|
- **Reentrancy (`ReentrantWriter` variants)**: Reentrancy is STRICTLY supported for
|
|
37
37
|
nested *write* operations by the same Thread/Task. It does NOT implicitly
|
|
38
38
|
grant read locks. You must use `.downgrade()` if you need to read.
|
|
39
|
-
- **Downgrade Performance Cost**: Calling `.downgrade()`
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
- **Downgrade Performance Cost**: Calling `.downgrade()` stores a single
|
|
40
|
+
downgrade-owner marker so the subsequent `release()` can safely route to
|
|
41
|
+
the read side. Standard fast paths remain allocation-free.
|
|
42
42
|
- **Circular References**: Base lock classes hold references to their proxies,
|
|
43
43
|
and proxies hold references back to the base. Memory is reclaimed via
|
|
44
44
|
Python's cyclic GC. Do not rely on `__del__` for cleanup.
|
|
45
45
|
|
|
46
46
|
Basic Example:
|
|
47
|
-
>>> lock =
|
|
47
|
+
>>> lock = RWLockWriteReentrantWriter()
|
|
48
48
|
>>> with lock.write:
|
|
49
49
|
... # Exclusive write access
|
|
50
50
|
... lock.write.downgrade()
|
|
@@ -64,4 +64,4 @@ Basic Example:
|
|
|
64
64
|
from .thread_rwlock import *
|
|
65
65
|
from .async_rwlock import *
|
|
66
66
|
|
|
67
|
-
__version__ = '3.
|
|
67
|
+
__version__ = '3.3'
|