C
C#2y ago
OptoCloud

❔ Can I Fire and forget ALOT of tasks? If so how do i do this efficiently?

I have a websocket connection, the server will always only have one task that reads from it, but after it has read the message and passed it onto the message handler i want it to begin reading the next message and forget the task it just started... This might result in alot of tasks being started, how do i do this in a efficient manner, or should i not do this at all?
9 Replies
OptoCloud
OptoCloudOP2y ago
Example class
public sealed class WebSocketInstance
{
private readonly WebSocket _webSocket;
private readonly ILogger<WebSocketInstance> _logger;

private async Task RunWebSocketAsync(CancellationToken cancellationToken)
{
while (_webSocket.State == WebSocketState.Open)
{
byte[] bytes = ArrayPool<byte>.Shared.Rent(4096);
try
{
WebSocketReceiveResult msg = await _webSocket.ReceiveAsync(bytes, cancellationToken);

// parse message into a body variable

await HandleMessageAsync(body.Value, cancellationToken); // I want to avoid await here
}
finally
{
ArrayPool<byte>.Shared.Return(bytes);
}
}
await CloseAsync();
}

private async Task<bool> HandleMessageAsync(ClientMessageBody message, CancellationToken cs)
{
// message handler logic that might call SendAsync and will probably access the this context
}

public async Task SendAsync(ServerMessageBody data, CancellationToken cs)
{
if (_webSocket.State != WebSocketState.Open) return;

// Send logic here
}
}
public sealed class WebSocketInstance
{
private readonly WebSocket _webSocket;
private readonly ILogger<WebSocketInstance> _logger;

private async Task RunWebSocketAsync(CancellationToken cancellationToken)
{
while (_webSocket.State == WebSocketState.Open)
{
byte[] bytes = ArrayPool<byte>.Shared.Rent(4096);
try
{
WebSocketReceiveResult msg = await _webSocket.ReceiveAsync(bytes, cancellationToken);

// parse message into a body variable

await HandleMessageAsync(body.Value, cancellationToken); // I want to avoid await here
}
finally
{
ArrayPool<byte>.Shared.Return(bytes);
}
}
await CloseAsync();
}

private async Task<bool> HandleMessageAsync(ClientMessageBody message, CancellationToken cs)
{
// message handler logic that might call SendAsync and will probably access the this context
}

public async Task SendAsync(ServerMessageBody data, CancellationToken cs)
{
if (_webSocket.State != WebSocketState.Open) return;

// Send logic here
}
}
Tinefol
Tinefol2y ago
Just fire the task and discard result? _ = Task.Run(() => HandleMessageAsync(body.Value, cancellationToken));
OptoCloud
OptoCloudOP2y ago
well yeah thats the easy way but i dont think thats smart memory usage n stuff
CoRoys
CoRoys2y ago
Why do you think so? CLR has garbage collection
OptoCloud
OptoCloudOP2y ago
im aware but this means allocating thousands of tasks that way the same way you would use ArrayPool<> instead of allocating arrays all the time, im asking this question because doing this at such a frequency might be bad
CoRoys
CoRoys2y ago
If you're worried about memory, then .NET will realloc as needed (when tasks finish executing). If you're worried about processing power, the thread pool thread takes care of that. It enqueues busy tasks as needed. That means when you're creating thousands of tasks in a short timespan, not all of them will be actively working
sibber
sibber2y ago
garbage collection isnt free (this also doesnt mean you should also micro optimize everything) anyway
_ = HandleMessageAsync(body.Value, cancellationToken);
_ = HandleMessageAsync(body.Value, cancellationToken);
will fire and forget but keep in mind your method will run sync-ly until the first await
cap5lut
cap5lut2y ago
in addition to what Cyberres said, there is also ValueTask/ValueTask<T> which are structs so u dont add additional work for the GC which can come in quite handy for fire and forget. ofc dont blindly use it but check out if it fits ur use cases https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.valuetask-1?view=net-7.0 https://devblogs.microsoft.com/dotnet/understanding-the-whys-whats-and-whens-of-valuetask/
Accord
Accord2y ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.
Want results from more Discord servers?
Add your server