I am making a simple TCP server and stumbled on this article by Marc Gravell mentioning the following:
Use ValueTask[], unless you absolutely can't because the existing API is Task[], and even then: at least consider an API break
So I changed my HandleClient()
method to return ValueTask
rather than Task
:
public async Task Start()
{
TcpListener.Start();
Console.WriteLine($"Server started. Listening on {ServerIP}:{ServerPort}");
while (true)
{
try
{
TcpClient client = await TcpListener.AcceptTcpClientAsync();
_ = HandleClient(client);
}
catch (Exception ex)
{
Console.WriteLine($"Error accepting client: {ex.Message}");
}
}
}
private async ValueTask HandleClient(TcpClient client)
{
...
int bytes = await stream.ReadAsync(buffer, cts.Token);
...
await stream.WriteAsync(response);
...
}
After changing the return type to ValueTask though, I am getting the following warning:
CA2012: ValueTask instances returned from method calls should always be used, typically awaited. Not doing so often represents a functional bug, but even if it doesn't, it can result in degraded performance if the target method pools objects for use with ValueTasks.
However, I cannot use await
here because the while loop has to keep running to accept connections concurrently while HandleClient()
executes on a different thread.
From this github issue, it is suggested to use HandleClient().Preserve()
, but doesn't that defeat the purpose of changing my method to ValueTask
since according to MSDN documentation:
You can use the Preserve() method to convert this ValueTask into the instance backed by a regular Task that is safe to await multiple times.
So, if I use Preserve()
then I am basically using a regular Task
from what I understand, and I might as well just change HandleClient()
back to return Task
instead.
I also tried assigning it to a variable and doing so does get rid of the warning, but I don't know if that solves the problem (if it even exists).
var t = HandleClient(client);
This assignment also does not give me the regular warning CS0129: The variable is assigned but its value is never used
, so maybe that is actually the solution?