我将此标记为.NET 4,因为我正在使用async BCL。
我有以下代码:
using System.Threading.Tasks;
public static async Task<ObservableCollection<MyResult>> GetMyData(Params p)
{
DoStuffClass stuff = new DoStuffClass();
ObservableCollection<MyResults> results = null;
await Task.Factory.StartNew(() =>
{
results = stuff.LongDrawnOutProcess(p);
});
return results;
}
我从之前的版本重构了一下,看起来像这样:
static void GetMyDataAsync(Params p, EventHandler<MyArgs> callback)
{
DoStuffClass stuff = new DoStuffClass();
stuff.LoadCompleted += callback;
stuff.LongDrawOutProcessAsync(p)
}
这方面的灵感来自here。
到目前为止,第一种情况的使用是最简单的,这就是我重构的原因;我的问题是:这种方法有什么缺陷吗? LongDrawnOutProcess
确实命中了数据库。
答案 0 :(得分:6)
您应该使用任务的Result
来访问Task
的结果,而不是依赖设置另一个变量的任务的副作用。虽然在这种情况下你没有过早地访问结果,但在使用这种编程风格时很容易犯错误。您还需要担心是否存在适当的内存屏障,以便正确观察更改后的变量。
更优选的方法是:
public static async Task<ObservableCollection<MyResult>> GetMyData(Params p)
{
DoStuffClass stuff = new DoStuffClass();
return await Task.Factory.StartNew(() => stuff.LongDrawnOutProcess(p));
}
接下来,由于除了返回值之外你在await
之后再也没有做任何事情,所以没有真正的理由在这里使用async
;你可以写:
public static Task<ObservableCollection<MyResult>> GetMyData(Params p)
{
DoStuffClass stuff = new DoStuffClass();
return Task.Factory.StartNew(() => stuff.LongDrawnOutProcess(p));
}
最后,这确实有一个更基本的问题。您没有使用实际的异步方法。您正在创建一个线程池线程,它将花费所有时间来等待此方法完成。这是浪费,异步编程的设计是避免这种同步等待,而不是将它们推送到另一个线程。如果你希望你的程序是异步的,你仍然应该使用Async
方法,但你仍然可以将它转换为基于任务的异步风格:
static Task<ObservableCollection<MyResult>> GetMyDataAsync(Params p)
{
var tcs = new TaskCompletionSource<ObservableCollection<MyResult>>();
DoStuffClass stuff = new DoStuffClass();
stuff.LoadCompleted += (args) => tcs.TrySetResult(args.Result);
stuff.LongDrawOutProcessAsync(p);
return tcs.Task;
}