0

I have the following method in my application

public async void Method()
{
    bool updated = false;

    foreach (Feed feed in Feeds)
    {
        if (await feed.Update())
        {
            updated = true; // At least one feed was updated
        }
    }

    if (updated)
    {
        // Do Something
    }
}

As you can see, the method Update() is called one by one, on each item in the list. I would instead like to call it on all the items simultaneously, and know whether one of them succeeded.

The method Update() is found in the class Feed

public async Task<bool> Update()
{
    try
    {
        WebRequest wr = WebRequest.Create(URL);
        wr.Timeout = 5000;

        using (WebResponse response = await wr.GetResponseAsync())
        {
            XmlDocument feed = new XmlDocument();
            feed.Load(response.GetResponseStream());

            // Do Something
            return true;
        }
    }
    catch (WebException we)
    {
        return false;
    }
}

EDIT:

So far I've been trying to solve this problem using async methods with and without return values.

public async void Update()
{
    if (await UpdateFeeds())
    {
        // Do something
    }
}

public async Task<bool> UpdateAllFeeds()
{
    // Update all the feeds and return bool
}

Then I realized I would still have the same problem within UpdateAllFeed(). They could run simultaneously if I changed Update() in Feed to an async void method, but then I would have no callback.

I don't know how to run multiple asynchronous methods and only callback when they're all done.

Servy
  • 202,030
  • 26
  • 332
  • 449
Expotr
  • 49
  • 6
  • 1
    Please don't just ask us to solve the problem for you. Show us how _you_ tried to solve the problem yourself, then show us _exactly_ what the result was, and tell us why you feel it didn't work. See "[What Have You Tried?](http://whathaveyoutried.com/)" for an excellent article that you _really need to read_. – John Saunders Mar 25 '15 at 16:52
  • Sorry about that. I'm still stuck in trying to figure out logically how to solve this problem using async methods with and without return (await) values. – Expotr Mar 25 '15 at 16:55
  • Store the `Task` returned by each call to `feed.Update` in a list or array and call `await Task.WhenAll` on the list. – Daniel Kelley Mar 25 '15 at 16:57
  • `Method` almost certainly shouldn't be `async void`. It should return a `Task` of some sort. – Servy Mar 25 '15 at 17:07
  • You should not be editing answers into the question. The question is where you ask a question. – Servy Mar 25 '15 at 17:21
  • Alright. It slipped my mind. I will remember. – Expotr Mar 25 '15 at 17:42

2 Answers2

4

Create a list of Task<bool> and then use Task.WhenAll

List<Task<bool>> tasks = new List<Task<bool>>();
foreach (var feed in feeds)
{
    tasks.Add(feed.Update());
}

await Task.WhenAll(tasks);

var updated = (from t in tasks where t.Result select t).Any();
John Koerner
  • 37,428
  • 8
  • 84
  • 134
  • 2
    `await Task.WhenAll` in this case returns a `bool[]`. You can also use `Select` to *project into a task* - a bit weird the first time you try it, but quite powerful: `bool[] results = await Task.WhenAll(feeds.Select(feed => feed.Update()));` – Stephen Cleary Mar 25 '15 at 19:29
-1
public async void Method()
{
  bool updated = false;

  Parallel.ForEach(Feeds, feed => 
  {
    if (feed.Update())
        updated = true; // At least one feed was updated
  });

  if (updated)
  {
    // Do Something
  }
}
jbriggs
  • 353
  • 2
  • 10
  • This seems like an odd solution. John's solution removes the requirement for additional threads whilst still running asychronously. – Daniel Kelley Mar 25 '15 at 17:03
  • @DanielKelley Well, the solution doesn't even *compile*, and if made to compile, and as it continues on without waiting for asynchronous operations so it wouldn't reliably work. That it's wasting the time of a bunch of threads (while certainly true) is the least of his problems. – Servy Mar 25 '15 at 17:06
  • Sorry forgot to remove the `await`. The OP asked `to call it on all the items simultaneously` the Parallel.ForEach makes small task and optimizes running them on all cores. see http://stackoverflow.com/questions/5009181/parallel-foreach-vs-task-factory-startnew The loop only returns after all task are complete – jbriggs Mar 25 '15 at 17:54
  • `Parallel.ForEach` makes sense to run CPU bound tasks in parallel but not I/O bound tasks. – Daniel Kelley Mar 26 '15 at 10:49