0

I have an I/O-bound task implemented with an async-await function.

At some point in this function, I receive some information which allows me to start a concurrent task, which is also I/O-bound (and so it is also implemented with an async-await function). My original task is not bound by this new task - I just need to set it going in the background.

If I do the following, I get warned that I'm not awaiting the call. I don't want to await the call! I want it to happen in the background!

async Task AnotherAsyncThing()
{
    // ...
}

async Task SomeAsyncThing()
{
    // ...

    // run concurrently - warning raised here
    Task.Run(async () => await AnotherAsyncThing());

    // ...
}

Am I missing something horribly obvious here? It feels like I am!

Archimaredes
  • 1,397
  • 12
  • 26
  • `SomeAsyncThing` doesn't need to be `asnyc`, only if it awaits something itself, which it doesn't, it should be `async` itself. Just an asside, though. – MakePeaceGreatAgain Aug 01 '22 at 12:26
  • 1
    As a side note, [fire-and-forget](https://stackoverflow.com/questions/61316504/proper-way-to-start-and-async-fire-and-forget-call/61320933#61320933) is frowned upon by the experts. – Theodor Zoulias Aug 01 '22 at 14:24
  • `I just need to set it going in the background.` And what code needs to know when it completes? What happens when it fails? – Stephen Cleary Aug 01 '22 at 22:38
  • @MakePeaceGreatAgain obviously it does await things in reality, I've added ellipses to denote code I've cut out - it's a minimal example. – Archimaredes Aug 02 '22 at 08:26
  • @StephenCleary Indeed. The situation: `SomeAsyncThing` should not call `AnotherAsyncThing` synchronously; I have no qualms about many `AnotherAsyncThing` calls occurring in parallel; `AnotherAsyncThing` does produce a result - right now, it enqueues the result for consumption in a different context. I currently have no decent idea what to do if `AnotherAsyncThing` throws an exception! – Archimaredes Aug 02 '22 at 14:20
  • 1
    @Archimaredes: Yes; I wasn't really looking for answers. Those questions were intended to make you rethink the design. Fire-and-forget is occasionally useful but almost always a mistake, for those reasons. If your code works fine when the operation doesn't complete (i.e., updating a distributed cache value), then f-a-f is fine. If you need to take some action when the operation doesn't complete (probably 99% of cases), then f-a-f is the wrong solution. Which is the whole point of the warning, and why it's a bad idea to just silence the warning without careful thought. – Stephen Cleary Aug 02 '22 at 19:19

2 Answers2

3

You can do something like this:

_ = AnotherAsyncThing()

This is the discards feature added in C# 7.0 and is a way of communicating the fact you're not interested in the return value to the compiler.

lee-m
  • 2,269
  • 17
  • 29
0

Yes and no :)

so often bugs occur when people forget to wait for tasks and it is considered a risk in APIs for instance to keep spinning up non awaited tasks because you can sometimes do so rapidly with bad performing client code and if that can steal many resources ... we'll i'm sure You can imagine.

But to signify that You know what You're doing and assume full responsibility, You can use the TPL like this and get rid of the warnings

_ = Task.Run(
        () => _ = AnotherAsyncThing()
    );

But each time this code is passed it will continue immediately and start something which will also continue to run. So Say your API gets a post, which accidentally happens every 10th millisecond instead of every 10th second as intended ... there is a danger in making the use of these things a standard.

It is a tool for a specific purpose, not the new white for walls, but yea You may have missed that we now should tell by using the nevermind underscore, that we know what we're doing this time and the compiler should back out from helping.

T. Nielsen
  • 835
  • 5
  • 18