1

I am executing a set of HTTP API commands on our embedded platform but need to add delays to ensure that the eventual GPIO operations are timed properly. I've followed a couple of examples from StackOverflow and Microsoft , but continue to have weird behavior.

I read a set of XML commands in to a list of Actions.

<action url="http://10.10.5.112/api/analogoutputs/0/3" delay="0"/>
<action url="http://10.10.5.112/api/analogoutputs/1/6" delay="5" />
<action url="http://10.10.5.112/api/analogoutputs/2/9" delay="10" />
<action url="http://10.10.5.112/api/analogoutputs/3/12" delay="15" />

Once read, the processing program initiates a set of calls to the ProcessHttpCallWithDelay method using Task.WhenAll:

IEnumerable<Task<bool>> httpCalls = 
  from Action in LogicActions
  select ProcessHttpCallWithDelay(Action.url, Action.delay);
// Make array of http calls
Task<bool>[] httpCallsArray = httpCalls.ToArray();
// Await the completion of all of the http calls
bool[] results = await Task.WhenAll(httpCallsArray);
// Process results
... do something with results ..

HTTP API processing method:

    private async Task<bool> ProcessHttpCallWithDelay(string url, int delay)
    {
        bool ok = true;
        try
        {
            await Task.Delay(delay*1000);
            WebRequest request = WebRequest.Create(url);
            request.ContentType = "application/json";
            HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync();
            string returnString = response.StatusCode.ToString();
            response.Close();
        }
        catch (Exception ex)
        {
            ok = false;
        }

        return ok;
    }

The problem is that the await Task.WhenAll(httpCallsArray) doesn't appear to await for all tasks to complete and moves on to the processing steps and no HTTP command is actually sent.

If I do a Task.WhenAll(httpCalls), using the IEnumerable, I do get one http command to be executed, but still the await for all tasks doesn't wait and moves to the processing step.

I would have expected in both cases to wait for all the WebResponses and returns from the ProcessHttpCallWithDelay method to finish. Can someone help me understand what might be going here?

Dave
  • 2,829
  • 3
  • 17
  • 44
HiDefLoLife
  • 555
  • 1
  • 8
  • 28
  • 1
    Your code for awaiting and creating the tasks is valid. Your code for creating your LogicActions however... lets see that – Dave Oct 05 '18 at 21:21
  • 1
    rough console approximation of what you https://dotnetfiddle.net/vYcQXQ. Works as expected – Dave Oct 05 '18 at 21:26
  • One thing that could explain the difference you see between using IEnumerable and Task[] is that when you created the collection of Task none of the tasks are executed I don't think until you evaluate the collection. When you call ToArray() the collection is evaluated and the task's begin all within a short time of each other. When you pass the IEnumerable to Task.WaitAll it potentially evaluates them in a foreach loop with other things happening in each iteration meaning that it might not fire them off as quickly and some how this is causing the diff in behaviour – Dave Oct 05 '18 at 21:32
  • Have you debug your code? Does the `LogicActions` have any item? – Farzin Kanzi Oct 05 '18 at 21:58
  • @Dave Thanks, I got it working. Two things that I noted of difference in your code, was the absence of the await on the Task.WaitAll() and the use of .Result on the Task.WaitAll() method. TBH, I'm not sure of the semantic difference in the underlying code changes, but it worked. If you'd like to answer and, optionally explain, I can accept the answer. – HiDefLoLife Oct 05 '18 at 22:18
  • 1
    The only reason I used `.Result` was I thought dotnetfiddle didn't allow async Main methods (it actually does). But I also tried it locally with await and got the same result. What `.Result` does in very simple terms is synchronously waits for the task to complete but there are LOTS of caveats. see https://stackoverflow.com/a/14527164/6915929 (and many many other SO posts). I won't post an answer as I didn't answer your question (it appears you did so you should post your own answer for others who may come in the future) – Dave Oct 05 '18 at 22:26
  • 1
    Some discussion of `WhenAll` vs. `WaitAll`, in case it helps: https://stackoverflow.com/questions/6123406/waitall-vs-whenall :) – Thogek Oct 05 '18 at 22:44

0 Answers0