User guide¶
See more examples in docs/examples
Installation¶
First off, install library with
Initialize UringioLoop¶
To start using uringio user need to initialize special io_uring loop - UringioLoop
Its quite simple:
Or with Runner:
File and Socket Operations¶
File operations¶
uringio.File object acts as interface to true asynchronous file operations in Python.
See full File API
You can import it by
Let's create simple example of writing and reading from file:- Open file asynchronously
- Write to file, asynchronously. Better use bytes in v0.4.4
- Read from file, again - asynchronously
- Closing file asynchronously
Now lets put it inside function:
async def file_simple_example():
file = await uringio.open_file(path='path/to/file.txt')
await file.write(data=b'Hello, uringio!\n')
await file.read()
await file.close()
Important note - you can await this function only with new UringioLoop loop.
See how easy it is actually to combine everything we know so far:
import asyncio
import uringio
async def file_simple_example():
file = await uringio.open_file(path='path/to/file.txt')
await file.write(data=b'Hello, uringio!\n')
await file.read()
await file.close()
asyncio.run(file_simple_example(), loop_factory=uringio.UringioLoop)
But actual code would be even simpler - with usage of file context manager
import asyncio
import uringio
async def file_simple_example():
async with await uringio.open_file(path='path/to/file.txt') as file:
await file.write(data=b'Hello, uringio!\n')
await file.read()
asyncio.run(file_simple_example(), loop_factory=uringio.UringioLoop)
asyncio.Runner when you need more control over the event loop:
Socket operations¶
uringio.Socket object acts as interface to asynchronous socket operations in Python using io_uring, not epoll.
See full Socket API
You can import it by
Let's create simple example of sending message from one socket to another:
- Prepare socket
- Bind to socket
- Listen socket
- Accept an incoming connection
- Receive data from the connection
- Send data through a socket
- Close the socket asynchronously
Now let's put everything together into a simple client-server example;
As with file operations, socket operations must be executed using the UringioLoop:
import asyncio
import uringio
async def socket_simple_example():
server_socket = await uringio.prep_socket()
await server_socket.bind('127.0.0.1', 12878)
await server_socket.listen()
client_socket = await uringio.prep_socket()
await client_socket.connect('127.0.0.1', 12878)
server_connection = await server_socket.accept()
await client_socket.send(b'Hello from client!')
received_data = await server_connection.recv()
await client_socket.close()
await server_connection.close()
await server_socket.close()
asyncio.run(socket_simple_example(), loop_factory=uringio.UringioLoop)
The server socket is bound to 127.0.0.1:12878 and starts listening for incoming connections.
The client then connects to the server, after which the server accepts the connection and receives the message sent by the client.
You can also use asyncio.Runner when you need more control over the event loop:
with asyncio.Runner(loop_factory=uringio.UringioLoop) as runner:
runner.run(socket_simple_example())
And there is support of context manager protocol:
import asyncio
import uringio
async def socket_simple_example():
async with await uringio.prep_socket() as server_socket:
await server_socket.bind('127.0.0.1', 12878)
await server_socket.listen()
async with await uringio.prep_socket() as client_socket:
await client_socket.connect('127.0.0.1', 12878)
async with await accept_future as server_connection:
await client_socket.send(b'Hello from client!')
received_data = await server_connection.recv()
asyncio.run(socket_simple_example(), loop_factory=uringio.UringioLoop)
Execution Context¶
To use advanced features, use different types of context managers.
Note that not all operations are supported in every context, but it will automatically dispatched to supported operation
TransferMode¶
To use operations in zero-copy mode, use UringioLoop.transfer_mode context manager, with uringio.TRANSFER_MODE Enum:
import asyncio
import uringio
async def transfer_mode():
loop = asyncio.get_running_loop()
with loop.transfer_mode(mode=uringio.TRANSFER_MODE.ZERO_COPY):
await simple_socket_example()
asyncio.run(transfer_mode(), loop_factory=uringio.UringioLoop)
NORMAL and ZERO_COPY values in TRANSFER_MODE Enum
StreamStrategy¶
To use Multishot operations, use stream_strategy context manager, with uringio.STREAM_STRATEGY Enum. In v0.4.4 its better to not use it:
import asyncio
import uringio
async def stream_strategy():
loop = asyncio.get_running_loop()
with loop.stream_strategy(stream=uringio.STREAM_STRATEGY.MULTISHOT):
await simple_socket_example()
asyncio.run(stream_strategy(), loop_factory=uringio.UringioLoop)
ONESHOT and MULTISHOT values in STREAM_STRATEGY Enum
BufferMode¶
To use operations in zero-copy mode, use UringioLoop.buffer_mode context manager with uringio.BUFFER_MODE Enum:
Fixed buffer mode¶
Note, FIXED buffer mode currently working only with files
import asyncio
import uringio
async def buffer_mode():
loop = asyncio.get_running_loop()
buf = bytearray(4096)
with loop.buffer_mode(mode=uringio.BUFFER_MODE.FIXED, buffers=[buf]):
await simple_file_example()
asyncio.run(buffer_mode(), loop_factory=uringio.UringioLoop)
There are NORMAL, FIXED, PROVIDED and BUF_RING values in BUFFER_MODE Enum
ExecutionContext¶
To set context manager with different types of all regimes above - use UringioLoop.execution_context context manager:
import asyncio
import uringio
async def execution_context():
loop = asyncio.get_running_loop()
buf = bytearray(4096)
with loop.execution_context(
stream_strategy=uringio.STREAM_STRATEGY.MULTISHOT,
buffer_mode=uringio.BUFFER_MODE.FIXED,
transfer_mode=uringio.TRANSFER_MODE.ZERO_COPY,
buffers=[buf],
):
await simple_file_example()
asyncio.run(buffer_mode(), loop_factory=uringio.UringioLoop)
If you face some problems, please leave an issue on Github