Update Akka.IO to use System.IO.Pipelines for reading from socket#4017
Update Akka.IO to use System.IO.Pipelines for reading from socket#4017IgorFedchenko wants to merge 3 commits intoakkadotnet:devfrom
Conversation
|
As a first step, had to update Akka to |
|
Sending byte arrays (which are getting from Even more then that, looking at the usage of With that said, currently sending data is blocking in the actor. Basically, when At least, this might me an issue when actor is actively sending and receiving messages of not-small-enough size. I do not thing that this might influent #4015 Akka.IO benchmark, because send-receive cycle there is sequencial and there should not be any commands waiting until the blocking @Aaronontheweb This optimization is not related to this PR directly, and can be done in separate PR. Should I make separate issue for this? This might be a good piece of work, because after performing blocking |
|
On mobile phone here so I'll be brief - love the idea of buffering write payloads on async write and doing them in batch, like you said
…Sent from my iPhone
On Nov 1, 2019, at 3:31 PM, Igor Fedchenko ***@***.***> wrote:
Sending byte arrays (which are getting from commander actor's messages) via network does not require Pipelines API, because we always getting ByteString of specific size and can just put it on the socket.
Even more then that, looking at the usage of protected SocketAsyncEventArgs SendArgs; defined, it is clear that it is not used, at all. It is acquired on connection start, and released to the pool once connection is finished. The only usage is passing to PendingBufferWrite helper class, but it is not used there at all.
With that said, currently sending data is blocking in the actor. Basically, when Write command is received, in ends up with been sent to the socket in the while loop (getting transferred bytes count until all data is sent). Instead, we could use socket.SendAsync(sendEventArgs) to perform operation asynchronously - in that case, actor could receive more messages until send operation is finished, and wait for it to finish only if another Write command is coming.
Or even enqueue incoming write commands and dequeue them once previous SendAsync is finished (in the callback). To not allow too much buffering we can start making send's blocking once buffer is growing (i.e. get getting another Write command, wait until current SendAsync finishes before putting new one into the queue). This is what Pipelines library does with their Pipe.
At least, this might me an issue when actor is actively sending and receiving messages of not-small-enough size. I do not thing that this might influent #4015 Akka.IO benchmark, because send-receive cycle there is sequencial and there should not be any commands waiting until the blocking Send will be finished.
@Aaronontheweb This optimization is not related to this PR directly, and can be done in separate PR. Should I make separate issue for this? This might be a good piece of work, because after performing blocking Send some other things are done and this should be accurately moved to the callback and not break actors internal state management.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or unsubscribe.
|
|
Now I got some understanding of how data receiving works in The way how receiving is implemented is fine: once connected, actor starts async reading with callback on finish, and in the callback sends There is no much profit of using So there is no much space for optimization. // reader is getting data from pipe.Writer, which is getting data from socket with minimal allocations
ReadResult result = await reader.ReadAsync();
ReadOnlySequence<byte> buffer = result.Buffer;
// Put obtained data to ByteString without allocations
var byteStringToSend = ByteString.CopyFrom(buffer); // Or mabe .Slice() call will be needed?
// Mark that part of buffer as already handled
reader.AdvanceTo(buffer.Start, buffer.End);This way we will not perform additional allocations, which may improve throughput. |
|
And one more thing we need to keep in mind that reading from socket to this pipe directly ( Update: just realized that to keep .NET Framework support, I will need to put some compiler directives to switch implementation between |
|
@IgorFedchenko my initial idea was to make Regarding Also there was an old |
|
@Horusiath About For modern async option I was going to use |
|
Updated So far, instead of just receiving data via First optimization we might get here is that we can start reading new data from socket right after it was read to the Second optimization is still in |
The code I removed was broken - IIRC sending order wasn't preserved due to how it was implemented. Opted for synchronous send just to simplify things and get the fix out there. Re-visiting things now to make better use of I/O wait times seems like a good idea. |
I think it might make things too complicated in the short run. Why don't we stick with fixing the |
Aaronontheweb
left a comment
There was a problem hiding this comment.
Need to change some global settings in order to stay on-target for 1.4 release.
| <NBenchVersion>1.2.2</NBenchVersion> | ||
| <ProtobufVersion>3.10.0</ProtobufVersion> | ||
| <NetCoreTestVersion>netcoreapp2.1</NetCoreTestVersion> | ||
| <NetCoreTestVersion>netcoreapp3.0</NetCoreTestVersion> |
There was a problem hiding this comment.
Hold off on this if you can - requires a much bigger set of changes on the build system side to support it.
| <NetStandardLibVersion>netstandard2.0</NetStandardLibVersion> | ||
| <NetFrameworkLibVersion>net452</NetFrameworkLibVersion> | ||
| <NetStandardLibVersion>netstandard2.1</NetStandardLibVersion> | ||
| <NetFrameworkLibVersion>net461</NetFrameworkLibVersion> |
There was a problem hiding this comment.
Once we figure out what to do with the parts of Akka.NET that depend on System.Configuration, we will drop explicit .NET Framework support and just stick to standard.
| <NetFrameworkTestVersion>net461</NetFrameworkTestVersion> | ||
| <NetStandardLibVersion>netstandard2.0</NetStandardLibVersion> | ||
| <NetFrameworkLibVersion>net452</NetFrameworkLibVersion> | ||
| <NetStandardLibVersion>netstandard2.1</NetStandardLibVersion> |
There was a problem hiding this comment.
Like I mentioned in PR comments, stick to .NET Standard 2.0 for the time being - we can add the pipelines stuff in later. Let's just get SocketAsyncEventArgs usage optimized / improved doing what we can for now.
|
@Aaronontheweb I am suggesting to keep this PR as is, because sooner or later we might be able to add So, it is still some progress for #3328 , but we will just hold this until the time we will be able to target And I will make performance fixes (like for #4018 ) in other PRs. |
Sounds good. |
|
after updated to .Net core 3.1, this could be merged sometime |
This is going to be a major part of work (if not the whole part) on the issue #3328 .
In particular, currently all sockets communication is implemented in
TcpConnectionactor class (with some helpers involved), and usesSocketAsyncEventArgsto handle connections. In this PR I am going to substitute this logic with usingPipeclass fromSystem.IO.Pipelines, which helps reading network stream.