Imagine I have connection in which I have to write numbers, represented by this contract:
interface ISocket
{
Task WriteAsync(Byte[], Int32 offset, Int32 count, CancellationToken cancel);
}
There is one single thread calling this WriteAsync
method.
Till now each caller to ISocket
was buffering independently and knows when it has to flush, however I would like to centralize that logic. Also I want to make sure that when such buffer is being transmitted, I can take advantage of async/await and release the thread pool thread.
My idea would be to create something like this:
class SocketWriter
{
private ISocket _socket;
private Byte[] _buffer; // assume 8K
private Int32 _cursor;
[ ... ]
private async Task FlushCacheIfNotEnoughSpace(Int32 length, CancellationToken cancel)
{
if(!FitsInBuffer(length))
{
await _socket.WriteAsync(_buffer, 0, _cursor, cancel).ConfigureAwait(false);
_cursor = 0;
}
}
[ ... ]
public async Task WriteAsync(UInt64 value, CancellationToken cancel)
{
await FlushCacheIfNotEnoughSpace(8, cancel).ConfigureAwait(false);
CopyToByteArray(value);
}
public Task Flush(CancellationToken cancel)
{
return FlushCacheIfAny(cancel);
}
}
There are some memory constraints, so I cannot create more than one of those Byte[]
buffers. CopyToByteArray
requires enough space in the _buffer
and increments _cursor
accordingly.
Note that FlushCacheIfNotEnoughSpace
only awaits if the given length does not fit the current buffer.
My intention is that when the buffer is not complete and there is space for another number this method call executes synchronously, or properly awaits using IO completion ports otherwise:
await _writer.WriteAsync(1UL, cancel).ConfigureAwait(false);
I wonder if there is a better or more elegant way of doing this, because it seems like a lot of "noise":
await _writer.WriteAsync(obj.Member1, cancel).ConfigureAwait(false);
await _writer.WriteAsync(obj.Member2, cancel).ConfigureAwait(false);
await _writer.WriteAsync(obj.Member3, cancel).ConfigureAwait(false);
await _writer.WriteAsync(obj.Member4, cancel).ConfigureAwait(false);