简体   繁体   中英

Asynchronous task makes program hang

I have a task that needs to call an http request to server and I do it like this:

public static async Task<BoundingBox> Transform(this BoundingBox boundingBox, string epsg) {
    ...
    var min = _httpClient.GetStringAsync("https://epsg.io/trans?x=435951&y=5549182&s_srs=25832&t_srs=3857");
    var max =  _httpClient.GetStringAsync("https://epsg.io/trans?x=435911&y=5549122&s_srs=25832&t_srs=3857");
    await Task.WhenAll(min, max);
    ...
}
priorityBb = bb.Transform("epsg:3857").GetAwaiter().GetResult();

But it makes my UI hang.

What is wrong with my code? Many thank for your comment.

You must await the Transform method, because the task returned is probably not completed yet instead of GetAwaiter().GetResult() . You'll probably never need to use these methods. GetResult() will block the current thread while the task is not completed.

This is a rough sketch, I have too little information about your structure:

public class MyResults
{
    public string Min {get;set;}
    public string Max {get;set;}
}

public static async Task<MyResults> Transform(this BoundingBox boundingBox, string epsg) {
    ...
    var minTask = _httpClient.GetStringAsync("https://epsg.io/trans?x=435951&y=5549182&s_srs=25832&t_srs=3857");
    var maxTask =  _httpClient.GetStringAsync("https://epsg.io/trans?x=435911&y=5549122&s_srs=25832&t_srs=3857");

    await Task.WhenAll(minTask, maxTask);

    // you can access the Results now, because all tasks are completed.
    return new MyResults { Min = minTask.Result, Max = minTask.Result };
}


public static async Task GetMyData()
{
    var myResults = await bb.Transform(".....");
    //              ^^^^^

    Console.WriteLine(myResults.Min);
    Console.WriteLine(myResults.Max);
}

If the caller isn't supporting async, you could try something like: (haven't tested it so, you'll have to check it)

The TaskScheduler.FromCurrentSynchronizationContext() is only needed when you are dealing with (for example) a UI thread.

public static void GetMyData()
{
    // You are not able to await it here. Fire and "forget"

    Task.Run<MyResults>(() =>
    {
        // Not executed on the UI thread
        return bb.Transform(".....");

    })
    .ContinueWith(transformTask =>
    {
        // back on the UI thread.....
        var myResults = transformTask.Result;

        Console.WriteLine(myResults.Min);
        Console.WriteLine(myResults.Max);

    }, TaskScheduler.FromCurrentSynchronizationContext());
}
priorityBb = bb.Transform("epsg:3857").GetAwaiter().GetResult();

This line is blocking your UI thread, because of call to GetResult . Earlier you used async / await correctly, but in this line you are mixing async code with blocking code. You should use same approach as in Transform method and await the result instead of blocking using GetResult

To fix this simply change that line to

priorityBb = await bb.Transform("epsg:3857");

Using GetResult like that can lead to deadlocks and in most situations is not a good idea. Whenever you can just stick to async / await .

If you can't make your caller async then your call can't be async . async / await is probably best approach here but if for some reason you can't use it you can wait for response and handle it on another thread using Task.Run

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