我有一个抽象类,其方法定义如下
public abstract class FooBase : IDisposable
{
protected abstract bool GetData(params object[] getDataParams);
}
我正在使用这样的抽象类并尝试异步运行GetData方法
public class SomeClass : FooBase
{
protected override bool GetData(params object[] getDataParams)
{
var task = Task.Factory.StartNew(() =>
{
using (var adapter = new DataAdapter())
{
// Take your time and fetch the data
}
});
task.Wait();
return true;
}
}
我想知道的是:我是做对还是错,或者是否还有其他更好的方法来达到同一目标。
如果我改变我的方法,那么它将被异步调用
public class SomeClass : FooBase
{
protected override bool GetData(params object[] getDataParams)
{
var task = Task.Factory.StartNew(async () =>
{
using (var adapter = new DataAdapter())
{
// Take your time and fetch the data
}
});
task.Wait();
return true;
}
}
感谢您对此的评论。
答案 0 :(得分:3)
除了同步之外,无法运行同步方法。
你可以将结果包装成看起来像异步运行的东西(例如。Task.FromResult
),或者在另一个线程中运行。 1 但是同步方法仍会阻塞线程它正在运行。
(相反,阻塞异步操作,很简单。这就是为什么你需要让底层操作异步,因为你可以在顶层构建同步和异步方法。)
更新(有关更新):
附加代码 - 特别是task.Wait()
语句 - 将导致调用者的线程在等待任务完成时阻塞。该任务将在另一个线程上运行,导致该线程被阻塞。 IE浏览器。你导致两个线程(调用者和一个线程池线程)阻塞。如果直接调用底层方法,则只会阻塞调用方的线程。
您有两种方法:
最佳:使用ADO.NET的异步操作。 (这意味着不使用DataTables
/ DataAdaptor
,但恕我直言,这是一个很好的举动:他们所做的就是将应该在数据库上进行的操作移到客户端。)
卸载到另一个线程,但向调用者返回Task<TResult>
,仅将Task
标记为完成,然后基础操作完成。类似的东西:
protected override Task<bool> GetData(params object[] getDataParams) {
var tcs = new TaskCompletionSource<bool>();
Task.Factory.StartNew(async () => {
using (var adapter = new DataAdapter()) {
// Take your time and fetch the data
tcs.SetResult(the-result);
}
});
return tcs.Task;
}
请注意,GetData
的返回值为Task<bool>
:调用者需要等待或同时执行其他操作,然后获取数据操作的结果。如果调用者只是等待,那么你有两个被阻塞的线程。 (C#5&#39; s await
不同:调用者也变得异步。)
1 为避免疑问:这可以看起来像一个正常的,Task<T>
返回的异步方法(例如,利用TaskCompletionSource<T>
卸载从当前线程阻塞到线程池中的某个线程)。但它仍然是一个阻塞操作:只是阻塞一个不同的线程。