0

I work with Node.js and so I got very used to its 'programming style' and its way to deal with asynchronous operations through higher order functions and callbacks, where most I/O events are handled in a async way by design and if I want to make a sync operation, I need to use Promises or the await shortcut, whereas in synchronous programming languages like Java, C#, C++ apparently I'd have to do the opposite, by somehow telling the compiler that the task I want to achieve must be performed asynchronously. I tried reading through the Microsoft docs and couldn't really understand how to achieve it. I mean, I could use Threads but for the simple task I want to process, exploring Threads is just not worth it for the trouble on guaranteeing thread-safety. I came across the Task class. So, suppose that I want to run a Task method multiple times in a async way, where the functions are being called in parallel. How can I do this?

        private Task<int> MyCustomTask(string whatever)
        {
           // I/O event that I want to be processed in async manner
        }

So basically, I wanted to run this method in 'parallel' without threading.

foreach (x in y)
{
   MyCustomTask("");
}

Bruno Giannotti
  • 323
  • 2
  • 13
  • It’s not at all clear what you’re asking. Are you looking for `private *async* Task`? – stuartd Mar 26 '20 at 22:06
  • Basically I want this method to be executed in 'parallel' without threading. Imagine this method being called inside a loop. – Bruno Giannotti Mar 26 '20 at 22:08
  • 1
    Here is an interesting reading: [Asynchronous programming with async and await](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/). It includes a usage example of the [`Task.WhenAll`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.whenall) method, that you probably want to learn for awaiting multiple concurrent I/O operations. – Theodor Zoulias Mar 26 '20 at 22:09
  • 1
    Does this answer your question? [Running multiple async tasks and waiting for them all to complete](https://stackoverflow.com/questions/25009437/running-multiple-async-tasks-and-waiting-for-them-all-to-complete) – devNull Mar 26 '20 at 22:11
  • No, I want the opposite. I don't want to wait. – Bruno Giannotti Mar 26 '20 at 22:11

2 Answers2

2

If you don't want to await, you can do something like this.

public class AsyncExamples
{
    public List<string> whatevers = new List<string> { "1", "2", "3" };

    private void MyCustomTask(string whatever)
    {
        // I/O event that I want to be processed in async manner
    }

    public void FireAndForgetAsync(string whatever)
    {
        Task.Run(
            () =>
            {
                MyCustomTask(whatever);
            }
        );
    }

    public void DoParallelAsyncStuff()
    {
        foreach (var whatever in whatevers)
        {
            FireAndForgetAsync(whatever);
        }
    }
}
derekbaker783
  • 8,109
  • 4
  • 36
  • 50
  • Thank you, that is exactly what I needed! – Bruno Giannotti Mar 26 '20 at 22:17
  • "Fire and forget" is almost always the wrong solution to whatever problem you actually have. "Forget" literally means **forget**, so it's only appropriate if you *don't care* if the code succeeds - or indeed, if it even runs to completion. – Stephen Cleary Mar 27 '20 at 00:26
  • @Stephen Cleary, I totally agree, but it's what the OP asked for. – derekbaker783 Mar 27 '20 at 00:45
  • 1
    Actually I needed a couple of things. I had a List of Tasks that were running the same async method with different parameters. I needed this methods to be fired concurrently. (With Tasks, not Workers, and that is also why I didn't want anything to do with Threads) In my code I'm actually returning data from each Task and I am running .WhenAll() to resolve my "promises" once they are completed. I was just stuck in how actually running a Task, since as far I was using it only as a type annotation for my methods and the documentation wasn't clear for me. – Bruno Giannotti Mar 27 '20 at 02:00
  • Though I do feel bad now knowing it was so simple. Thanks guys – Bruno Giannotti Mar 27 '20 at 02:17
1

most I/O events are handled in a async way by design and if I want to make a sync operation, I need to use Promises or the await shortcut

I believe the difference you're expressing is the difference between functional and imperative programming, not the difference between asynchronous and synchronous programming. So I think what you're saying is that asynchronous programming fits more naturally with a functional style, which I would agree with. JavaScript is mostly functional, though it also has imperative and OOP aspects. C# is more imperative and OOP than functional, although it grows more functional with each year.

However, both JavaScript and C# are synchronous by default, not asynchronous by default. A method must "opt in" to asynchrony using async/await. In that way, they are very similar.

I tried reading through the Microsoft docs and couldn't really understand how to achieve it.

Cheat sheet if you're familiar with asynchronous JavaScript:

  • Task<T> is Promise<T>
    • If you need to write a wrapper for another API (e.g., the Promise<T> constructor using resolve/reject), then the C# type you need is TaskCompletionSource<T>.
  • async and await work practically the same way.
  • Task.WhenAll is Promise.all, and Task.WhenAny is Promise.any. There isn't a built-in equivalent for Promise.race.
  • Task.FromResult is Promise.resolve, and Task.FromException is Promise.reject.

So, suppose that I want to run a Task method multiple times in a async way, where the functions are being called in parallel. How can I do this?

(minor pedantic note: this is asynchronous concurrency; not parallelism, which implies threads)

To do this in JS, you would take your iterable, map it over an async method (resulting in an iterable of promises), and then Promise.all those promises.

To do the same thing in C#, you would take your enumerable, Select it over an async method (resulting in an enumerable of tasks), and then Task.WhenAll those tasks.

var tasks = y.Select(x => MyCustomTask(x)).ToList();
await Task.WhenAll(tasks);
Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • I don't think I was expressing this difference between imperative and functional programming, even though after you mentioned it, it does make sense. When I said: `most I/O events are handled in a async way by design and if I want to make a sync operation, I need to use Promises or the await shortcut`, I meant that in Nodejs is expected behaviour that most of these events returns Promises (for Js is widely used as an event driven language) and we get really used to dealing with them. I was just trying to find the correct "mapping" for single threaded Js Promises to C# Tasks. – Bruno Giannotti Mar 27 '20 at 02:11
  • Thank you for your inputs though, they were really helpful in the sense of clarifying both JS and C# worlds. – Bruno Giannotti Mar 27 '20 at 02:15