Skip to content

Commit 02a7001

Browse files
develop
1 parent 2f0a061 commit 02a7001

File tree

100 files changed

+4510
-1
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

100 files changed

+4510
-1
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,6 @@ venv.bak/
102102

103103
# mypy
104104
.mypy_cache/
105+
106+
# cffi
107+
*_cffi.*

.travis.yml

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
dist: xenial
2+
sudo: true
3+
language: python
4+
git:
5+
depth: 10
6+
branches:
7+
only:
8+
- master
9+
- /develop/
10+
matrix:
11+
include:
12+
- python: 3.8
13+
env: TOXENV=py38
14+
install:
15+
- pip install tox devrepo
16+
script:
17+
- echo $HOME
18+
- uname -a
19+
- ip addr
20+
- python --version
21+
- tox

README.md

-1
This file was deleted.

LICENSE licence

File renamed without changes.

readme.md

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
2+
## data_pipe
3+
4+
[![Travis Status][travis_icon]][travis_link]
5+
[![Package Version][pypi_icon]][pypi_link]
6+
[![Python Versions][python_icon]][python_link]
7+
8+
### Features
9+
10+
Cross Thread Message Pipe:
11+
* lock-free
12+
* thread-safe
13+
* exponential-back-off
14+
15+
Message Transfer End Points:
16+
* any combination of: sync, trio, curio, asyncio
17+
18+
### Benchmark
19+
20+
Performance on local CPU:
21+
22+
cross-thread
23+
```
24+
sync -> sync @ 1.0 micros/object
25+
sync -> curio @ 5.0 micros/object
26+
sync -> asyncio @ 6.0 micros/object
27+
sync -> trio @ 7.0 micros/object
28+
```
29+
30+
cross-process
31+
```
32+
sync -> sync @ 0.5 micros/object
33+
sync -> curio @ 0.7 micros/object
34+
sync -> asyncio @ 0.7 micros/object
35+
sync -> trio @ 0.7 micros/object
36+
```
37+
38+
### Install
39+
40+
To install python package:
41+
42+
```
43+
sudo pip install data_pipe
44+
```
45+
46+
### Usage
47+
48+
study:
49+
* [any_ruptor_perf.py](https://github.com/random-python/data_pipe/blob/master/src/perf/data_pipe_perf/any_ruptor_perf.py)
50+
51+
52+
53+
54+
[travis_icon]: https://travis-ci.org/random-python/data_pipe.svg?branch=master
55+
[travis_link]: https://travis-ci.org/random-python/data_pipe/builds
56+
57+
[pypi_icon]: https://badge.fury.io/py/data-pipe.svg
58+
[pypi_link]: https://pypi.python.org/pypi/data-pipe
59+
60+
[python_icon]: https://img.shields.io/pypi/pyversions/data_pipe.svg
61+
[python_link]: https://pypi.python.org/pypi/data-pipe
62+
63+
[tokei_icon]: https://tokei.rs/b1/github/random-python/data_pipe
64+
[tokei_link]: https://github.com/random-python/data_pipe/tree/master/src

requirements-dev.txt

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
2+
cffi >= 1.13.2
3+
4+
numba >= 0.46.0
5+
6+
numpy >= 1.17.4
7+
8+
trio >= 0.13.0

requirements.txt

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
trio >= 0.13.0
3+
4+
curio >= 0.9

setup.cfg

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
[metadata]
2+
3+
name = data_pipe
4+
version = 0.1.5
5+
6+
requires-python = >=3.8
7+
8+
author = Andrei Pozolotin
9+
author-email = [email protected]
10+
11+
summary = Cross Thread Message Pipe
12+
13+
description-file = readme.md
14+
description-content-type = text/markdown; charset=UTF-8
15+
16+
home-page = https://github.com/random-python/data_pipe
17+
18+
license = Apache-2
19+
20+
classifier =
21+
Development Status :: 4 - Beta
22+
Intended Audience :: Developers
23+
License :: OSI Approved :: Apache Software License
24+
Operating System :: POSIX :: Linux
25+
Programming Language :: Python
26+
Programming Language :: Python :: 3.8
27+
Topic :: Utilities
28+
29+
30+
keywords =
31+
cross
32+
thread
33+
message
34+
pipe
35+
memory
36+
channel
37+
trio
38+
asyncio
39+
threading
40+
41+
[files]
42+
# none
43+
44+
[options]
45+
46+
packages =
47+
data_pipe
48+
data_pipe_test
49+
50+
package_dir =
51+
data_pipe = src/main/data_pipe
52+
data_pipe_test = src/test/data_pipe_test
53+
54+
[entry_points]
55+
# none
56+
57+
console_scripts =
58+
# none
59+
60+
[pbr]
61+
62+
warnerrors = True
63+
skip_authors = True
64+
skip_git_sdist = False
65+
skip_changelog = True

setup.py

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#!/usr/bin/env python
2+
3+
from setuptools import setup, Extension
4+
5+
setup(
6+
7+
pbr=True,
8+
9+
setup_requires=[
10+
"pbr",
11+
"cython"
12+
],
13+
14+
ext_modules=[
15+
Extension(
16+
name="data_pipe.runtime_library",
17+
sources=[
18+
"src/main/data_pipe/runtime_library.pyx",
19+
],
20+
),
21+
]
22+
23+
)

src/main/data_pipe/.gitignore

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
# generated resources
3+
4+
*.c
5+
*.so
6+
*.html

src/main/data_pipe/__init__.py

Whitespace-only changes.

src/main/data_pipe/any_buffer.py

+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
"""
2+
"""
3+
4+
import time
5+
import math
6+
import trio
7+
import curio
8+
import asyncio
9+
10+
from typing import Any
11+
from dataclasses import dataclass, field
12+
from trio._core._run import GLOBAL_RUN_CONTEXT
13+
14+
from data_pipe.any_index import AnyIndexBase
15+
16+
17+
class AnyBufferBase:
18+
""
19+
20+
default_wait_size = 15
21+
default_wait_list = [10e-6 * (2 ** index) for index in range(default_wait_size - 1, -1, -1)]
22+
23+
@classmethod
24+
def has_trio_loop(cls) -> bool:
25+
""
26+
return hasattr(GLOBAL_RUN_CONTEXT, "runner")
27+
28+
@classmethod
29+
def has_curio_loop(cls) -> bool:
30+
""
31+
return curio.meta.curio_running()
32+
33+
@classmethod
34+
def has_asyncio_loop(cls) -> bool:
35+
""
36+
return asyncio._get_running_loop() is not None
37+
38+
@classmethod
39+
async def perform_wait(cls, wait_time:float) -> None:
40+
""
41+
if cls.has_trio_loop():
42+
await trio.sleep(wait_time)
43+
elif cls.has_curio_loop():
44+
await curio.sleep(wait_time)
45+
elif cls.has_asyncio_loop():
46+
await asyncio.sleep(wait_time)
47+
else:
48+
assert False, f"wrong async"
49+
50+
@classmethod
51+
def perform_wait_sync(cls, wait_time:float) -> None:
52+
""
53+
time.sleep(wait_time)
54+
55+
56+
@dataclass(frozen=True)
57+
class AnyBufferCore(AnyBufferBase):
58+
""
59+
60+
ring_size:int = field(default=128)
61+
wait_list:list = field(default_factory=lambda:AnyBufferBase.default_wait_list, repr=False)
62+
63+
_ring_array:list = field(default=None, repr=False, init=False)
64+
_ring_index:AnyIndexBase = field(default_factory=AnyIndexBase, repr=False, init=False)
65+
66+
def __post_init__(self):
67+
""
68+
assert math.log(self.ring_size, 2).is_integer(), f"wrong ring_size={self.ring_size}"
69+
_ring_array = [ None for _ in range(self.ring_size) ]
70+
object.__setattr__(self, '_ring_array', _ring_array)
71+
self._ring_index.setup(ring_size=self.ring_size, wait_size=len(self.wait_list))
72+
73+
async def invoke_reader(self) -> Any:
74+
""
75+
while True:
76+
index = self._ring_index.next_reader()
77+
if index < 0:
78+
await self.perform_wait(self.wait_list[index])
79+
else:
80+
return self._ring_array[index]
81+
82+
def invoke_reader_sync(self) -> Any:
83+
""
84+
while True:
85+
index = self._ring_index.next_reader()
86+
if index < 0:
87+
self.perform_wait_sync(self.wait_list[index])
88+
else:
89+
return self._ring_array[index]
90+
91+
async def invoke_writer(self, value:Any) -> None:
92+
""
93+
while True:
94+
index = self._ring_index.next_writer()
95+
if index < 0:
96+
await self.perform_wait(self.wait_list[index])
97+
else:
98+
self._ring_array[index] = value
99+
return
100+
101+
def invoke_writer_sync(self, value:Any) -> None:
102+
""
103+
while True:
104+
index = self._ring_index.next_writer()
105+
if index < 0:
106+
self.perform_wait_sync(self.wait_list[index])
107+
else:
108+
self._ring_array[index] = value
109+
return
110+
#
111+
#
112+
#
113+
114+
get = invoke_reader_sync
115+
put = invoke_writer_sync

src/main/data_pipe/any_index.py

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
"""
2+
"""
3+
4+
5+
class AnyIndexBase:
6+
""
7+
8+
def setup(self, *, ring_size:int, wait_size:int) -> None:
9+
""
10+
11+
def next_reader(self) -> int:
12+
""
13+
14+
def next_writer(self) -> int:
15+
""

src/main/data_pipe/basic_buffer.py

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
"""
2+
"""
3+
4+
from dataclasses import dataclass, field
5+
6+
from data_pipe.any_buffer import AnyBufferCore
7+
from data_pipe.basic_index import BasicIndex
8+
9+
10+
@dataclass(frozen=True)
11+
class BasicBuffer(AnyBufferCore):
12+
""
13+
14+
_ring_index:BasicIndex = field(default_factory=BasicIndex, repr=False)

0 commit comments

Comments
 (0)