1

For example I have some synchronous functions that I want to run in another thread. I found the way with closure like this. Is there any more efficient and beautiful way if i don't want to create any new functions? Am I reinventing the wheel or is it alright?

class Program
{
    static void Main(string[] args)
    {
        ((Action)(async () =>
        {
            await Task.Run(() => LongOperation());
            Console.WriteLine("Then callback triggered");
        }))();

        Console.WriteLine("Main thread finished first.");

        Console.ReadKey();
    }

    static void LongOperation()
    {
        Thread.Sleep(3000);
        Console.WriteLine("Work completed");
    }
}

If I want just to perform the function asynchronously I can just type

Task.Run(() => LongOperation());

But what if I want to add some lines of code for callback like in JavaScript?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Liam Kernighan
  • 2,335
  • 1
  • 21
  • 24
  • 1
    You can use Task.ContinueWith for chaining asynchronous calls. – Thangadurai Mar 10 '18 at 08:14
  • 1
    If I understand you correctly you want to start an asynchronous operation don’t want to wait for it to finish in the main thread, but be notified when it completes. If so just write `Task.Run(() => LongOperation()).ContinueWith(task => Console.WriteLine("Then callback triggered");` without an await. – ckuri Mar 10 '18 at 08:15
  • 2
    You might want to read [this](https://blog.stephencleary.com/2013/11/taskrun-etiquette-examples-dont-use.html). Async/Await is not meant to be used for blocking operations. – ProgrammingLlama Mar 10 '18 at 08:15
  • 1
    I agree with @john that you should read this article first. Bottom line, use `Task.Run` only if your `LongOperation` method is CPU-bound. – 41686d6564 stands w. Palestine Mar 10 '18 at 08:17
  • 3
    Agree also with @john - async/await is for releasing the thread while performing an IO operation. Which also means, if you were to use async/await in the above example, Thread.Sleep() wouldn't demonstrate the desired behaviour, you'd need a Task.Delay. – Ben Hall Mar 10 '18 at 08:38
  • 1
    @AhmedAbdelhameed **never ever ever** use `async/await` for **cpu**-bound tasks. for this purpose `Parallel.For` exists. `Task` is meant to serve **IO**-bound stuff. – Zazaeil Mar 10 '18 at 09:13
  • 2
    @SerejaBogolubov There's nothing wrong with using `Task.Run(() => CpuBoundMethod())`, it's actually recommended. Read Stephen Cleary's [Task.Run Etiquette article](https://blog.stephencleary.com/2013/11/taskrun-etiquette-examples-dont-use.html), and also check [this one](https://blog.stephencleary.com/2014/04/a-tour-of-task-part-0-overview.html), specifically the _"Two Types of Task"_ section. `Parallel.For`, on the other hand, is for when you want to execute the same method on a number of items. Check [this question](https://stackoverflow.com/q/5009181/4934172). – 41686d6564 stands w. Palestine Mar 10 '18 at 09:42

2 Answers2

2

you are creating lambda-expression here:

Task.Run(() => LongOperation());

it can contain multiple statements:

Task.Run(() =>
         {
            LongOperation();
            Console.WriteLine("Then callback triggered");
         });
ASh
  • 34,632
  • 9
  • 60
  • 82
1

What is unclear from your post, is whether LondOperation() is CPU-bound or just IO-bound. Depending upon the answer you may prefer Parallel.For(...) or ...AsParallel()... provided by LINQ if you're dealing with collections for CPU-bound stuff; otherwise, for IO-purposes, Task is the best natively .NET supported choice (just to know there are other common approaches like rX - "reactive extensions", however Task framework outperforms those remarkably).

As other guys have shown already, there are continuations allowing you to sequence async calls; moreover, there are .WhenAll/.WhenAny which are helpful in many typical "enterprise" situations. And yet you can wrap sync code into async containers in a Task.Run(...) fashion.

Zazaeil
  • 3,900
  • 2
  • 14
  • 31
  • "The purpose of Task.Run is to execute CPU-bound code in an asynchronous way" - https://blog.stephencleary.com/2013/10/taskrun-etiquette-and-proper-usage.html – Dave Mar 10 '18 at 09:27
  • yeah : ) `Task.Run` is just a wrapper, that pushes execution of it's internals to the thread pool. All the rest done apart from the `Task` framework. My experience shows that being explicit when dealing with CPU stuff is much better yet more potentially better in performance terms, rather than having single API everywhere; especially when it forces you to return `Task` and propagate async/await through the entire call stack. – Zazaeil Mar 10 '18 at 09:37