简体   繁体   中英

async method not run asynchronously

I am writing below code in WPF. However, it does not run asynchronously. I have commented the line where the code gets blocked. Please let me know where am I doing the mistake.

private async void txtSampleRequest_Click(object sender, RoutedEventArgs e)
{
    await DownloadData();
}
        
async  Task<string> DownloadData()
{
    string authorization = txtAuthentication.Text;
    string cookie = txtCookie.Text;

    try
    {
        var vvv = Enumerable.Range(0, 50);

        List<Task> TaskList = new List<Task>();
        foreach (int s in vvv)
        {
            Task LastTask = ZerodhaOperations.MyHttpRequest("", authorization, cookie, "5minute");//Even this method is async method, and I have added dummy Task.Delay(1) to run method asynchronously. Below is the full definition of this class.
            TaskList.Add(LastTask);
        }

        await Task.WhenAll(TaskList);  //<------------ Here it stops working asynchronously and blocks UI of application. 
        MessageBox.Show("DONE");
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }

    return "";
}
class ZerodhaOperations
{
    public static async Task<string> MyHttpRequest(string WEBSERVICE_URL,string authorization, string cookie,string timeFrame)
    {
        await Task.Delay(1);
        if (authorization == "" || cookie == "" || authorization == null || cookie == null)
        {
            throw new ArgumentException("Aditya Says, No Authorization and cookie has been set");
        }
        string jsonResponse = "";
        WEBSERVICE_URL = "https://kite.zerodha.com/oms/instruments/historical/519937/timeFrame?user_id=YD0744&oi=1&from=2020-04-24&to=2020-04-24";
        WEBSERVICE_URL = $"https://kite.zerodha.com/oms/instruments/historical/806401/{timeFrame}?user_id=YD0744&oi=1&from=2020-12-03&to=2020-12-03";

        try
        {
            var webRequest = System.Net.WebRequest.Create(WEBSERVICE_URL);

            //ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
            ServicePointManager.Expect100Continue = true;
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls
                   | SecurityProtocolType.Tls11
                   | SecurityProtocolType.Tls12
                   | SecurityProtocolType.Ssl3;
            ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };

            if (webRequest != null)
            {
                webRequest.Method = "GET";
                webRequest.Timeout = 5000;

                if (authorization != "")
                {
                    webRequest.Headers.Add("authority", "kite.zerodha.com");
                    webRequest.Headers.Add("authorization", authorization);
                }

                webRequest.Headers.Add("cookie", cookie);
                webRequest.Headers.Add("method", "GET");

                using (System.IO.Stream s = webRequest.GetResponse().GetResponseStream())
                {
                    using (System.IO.StreamReader sr = new System.IO.StreamReader(s))
                    {
                        jsonResponse = sr.ReadToEnd();
                        if (jsonResponse == "")
                            throw new Exception("Empty Response");

                        //MessageBox.Show(jsonResponse);
                    }
                }
            }
        }
        catch (Exception ex)
        {
            if (ex.Message.Contains("Empty Response"))
                throw ex;
            else
                MessageBox.Show(ex.ToString());
        }

        return jsonResponse;
    }
}

The way await works is that it captures a "context" when it asynchronously yields. The details are in the link, but in this case the asynchronous method is running on the WPF UI thread, so it captures a context that will resume running on that UI thread.

So the await Task.Delay(1) is in fact forcing MyHttpRequest to act asynchronously, but it's what happens next that is tripping you up. MyHttpRequest does the await , which captures the UI context and returns an incomplete task. This happens multiple times in DownloadData , which collects the incomplete tasks and then await s the Task.WhenAll of them. So then DownloadData returns an incomplete task which is await ed by the event handler, which returns control back to the WPF message loop.

Now, what happens next is that those Task.Delay timers fire off almost immediately. So, MyHttpRequest resumes its async method, and since its await captured that UI context, it resumes running on the UI thread . So the await Task.Delay(1) did cause a yield to the WPF message loop, but then practically the very next thing the UI thread has to do is resume those async methods.

And the remainder of those async methods are synchronous, blocking the UI thread.

So, to solve this, you can make the methods truly asynchronous. Delete the await Task.Delay(1) completely and instead replace the synchronous APIs with asynchronous ones ( GetResponseAsync , ReadToEndAsync ). Or if you want to modernize the code further, replace WebRequest with HttpClient .

Your other option is to keep the code synchronous and just use Task.Run to run the synchronous code on background threads. Again, you would delete the await Task.Delay(1) , and this time you would change the method signature to be synchronous. Then you can wrap the call to the (synchronous) MyHttpRequest in a Task.Run , eg, Task LastTask = Task.Run(() => ZerodhaOperations.MyHttpRequest("", authorization, cookie, "5minute")); The Task.Run solution is less ideal than the asynchronous solution, but it is acceptable if you have a lot of other code that still needs MyHttpRequest to be synchronous for now.

Note that either way, the usage of Task.Delay(1) is wrong. It does not "run [the] method asynchronously". The proper way to run a method asynchronously is to have it call asynchronous APIs and not call blocking APIs.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM