-3

Suppose, I have a simple class, with async method in it:

public class Writer
{
    public Task WriteAsync(string message);
}

This is internal class, which is absolutely negligible for application's business logic.

The main idea of the method, is that when it's called - method must immediately returns control to the calling method, to avoid any possible delay in important, full of business logic calling method (delay for calling that method is possible of course).

This method calls in different places, very often. and we don't really care if it's successful or won't write last messages in case of unexpectable situation. That's fine.

So, the question is, how can I call WriteAsync to avoid any possible delays in calling method?

I thought about Task.Run(() => WriteAsync(message)) (without await! we don't need to wait this!), but won't that fill my thread pool with a lot of useless work? And it's quite onerously writing everywhere such code...

Yurii N.
  • 5,455
  • 12
  • 42
  • 66
  • 1
    Possible duplicate of [Fire-and-forget with async vs "old async delegate"](https://stackoverflow.com/questions/12803012/fire-and-forget-with-async-vs-old-async-delegate) – Gabriel Luci Dec 11 '18 at 15:39
  • 4
    If what the method does is useless, and if it doesn't matter if the method succeeds or not... Why have it at all? – David Dec 11 '18 at 15:39
  • Tasks are pretty light in that sense, unless the implementation is heavy by itself, if your concern is about how to fire and forget the task, just create a void method that runs Task.Run(() => WriteAsync(message))..., however like David said, if that main thread is terminated, the task will be terminated, therfore, do you really need this ? – MrVoid Dec 11 '18 at 15:40
  • If it's truly "useless", then don't do it :) But if you want it to run, then you have no choice but to spend the processing power to do it. What you want is commonly called "fire and forget" (run it in the background and ignore it). And keep in mind that [a Task doesn't necessarily run on its own thread](https://stackoverflow.com/a/34155266/1202807), although it might. – Gabriel Luci Dec 11 '18 at 15:41
  • @David this is special method, which is originally adds metrics to `InfluxDb`, it's just a simple example. – Yurii N. Dec 11 '18 at 15:43
  • You may queue the writes and process the queue, i.e. perform the writing, on a background thread. This is kind of what happens when you call `Task.Run`, i.e. you queue up delegates in the thread pool. If you require more control, you may for example use a `BlockingCollection`. – mm8 Dec 11 '18 at 15:44
  • @mm8 maybe that's exactly what I need, a dedicated thread for such operations. – Yurii N. Dec 11 '18 at 15:45
  • @YuriiN.: It sounds like this is what you want. There is an example of how to use the `BlockingCollection` class available on [MSDN](https://learn.microsoft.com/en-us/dotnet/api/system.collections.concurrent.blockingcollection-1?view=netframework-4.7.2) – mm8 Dec 11 '18 at 15:47

2 Answers2

1

You may queue the writes and process the queue, i.e. perform the writing, on a dedicated background thread. This is kind of what happens when you call Task.Run, i.e. you queue up delegates in the thread pool. If you require more control, you may for example use a BlockingCollection<T>.

There is an example of how to use a BlockingCollection<T> to read and write items concurrently available on MSDN.

Using this approach, calling WriteAsync will only block for the time it takes to add the message to the queue and this time should be negligible.

mm8
  • 163,881
  • 10
  • 57
  • 88
0

Because the method is asynchronous then, by definition, it is already returning control to the caller immediately. If the implementation of that method isn't actually asynchronous, then it should either not return a Task, not have Async in the name, and make it clear to callers that it's synchronous, or it should fix the bug in its implementation that makes it block the caller for an extended period of time. Callers of the method will rightfully expect that, being an asynchronous method, it will return control to the caller immediately by just calling the method normally. If the method has a bug in it that makes it not do that, you shouldn't work around that bug and have callers treat it as a synchronous method when it claims it isn't.

Servy
  • 202,030
  • 26
  • 332
  • 449
  • Sorry for my incomprehension, but what shall we do when if implementation is synchronous, but time and resources consuming? You may say that we shall use `Task.Run` and it's fine, and that's what I want to avoid, littering my thread pool with useless threads. – Yurii N. Dec 11 '18 at 17:23
  • @YuriiN. If the method is synchronous then *why is it returning a `Task` and why does it have `Async` in the name*? If it's synchronous, and can't be made to be asynchronous then, *it shouldn't return a `Task` and shouldn't claim to be asynchronous in its name*. – Servy Dec 11 '18 at 18:04
  • It can be asynchronous just fine... except first synchronous portion (i.e. prepare data for write) can take 10 seconds, then proper `await` to perform asynchronous part (i.e. write to DB)... – Alexei Levenkov Dec 12 '18 at 05:27
  • @AlexeiLevenkov Then it's not actually an asynchronous method. It shouldn't be doing time consuming synchronous work in a method that's marked as asynchronous. If it has time consuming synchronous work to do it should be running that in a thread pool thread, rather than doing it synchronously in a method claiming to be asynchronous, and forcing every single caller of the method to work around that bug. – Servy Dec 12 '18 at 14:21