我有一个任务需要向服务器调用http请求,我这样做:
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();
但它让我的UI挂起了。
我的代码出了什么问题?非常感谢您的评论。
您必须等待Transform
方法,因为返回的任务可能还没有完成,而不是GetAwaiter().GetResult()
。您可能永远不需要使用这些方法。GetResult()
将在任务未完成时阻塞当前线程。
这是一个粗略的草图,我对你的结构信息太少:
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);
}
如果调用者不支持异步,您可以尝试以下操作:(还没有测试过,所以您必须检查它(
只有在处理(例如(UI线程时才需要TaskScheduler.FromCurrentSynchronizationContext()
。
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();
由于对GetResult
的调用,此行阻塞了您的UI线程。前面您正确地使用了async
/await
,但在这一行中,您将异步代码与阻塞代码混合在一起。您应该使用与Transform
方法和await
相同的方法,而不是使用GetResult
进行阻塞
要解决此问题,只需将该行更改为
priorityBb = await bb.Transform("epsg:3857");
像那样使用GetResult
可能会导致死锁,在大多数情况下这不是一个好主意。只要你能坚持async
/await
。
如果你不能让你的来电者成为async
,那么你的电话就不能是async
。async
/await
可能是最好的方法,但如果由于某种原因您无法使用它,您可以等待响应,并使用Task.Run
在另一个线程上处理它