运行 异步同步方法的正确方法是什么

What is the correct way to run synchronous method in asynchronously

我有一个抽象class,其方法定义如下

public abstract class FooBase : IDisposable
{
    protected abstract bool GetData(params object[] getDataParams);
}

我正在像这样使用这个抽象 class 并尝试异步 运行 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;
    }
}

感谢您对此的评论。

没有办法 运行 除了同步之外的同步方法。

您可以将结果包装在看起来像 运行 异步的东西中(例如 Task.FromResult),或者 运行 在另一个线程中。1 但是同步方法仍然会阻塞它 运行 正在运行的线程。

(相反,阻塞异步操作是微不足道的。这就是为什么你需要让底层操作异步,因为你可以在上面构建同步和异步方法。)

更新(有问题的更新):

该附加代码——特别是 task.Wait() 语句——将导致调用者的线程在等待任务完成时阻塞。该任务将 运行 在另一个线程上导致该线程阻塞。 IE。您正在导致两个线程(调用者和线程池线程)阻塞。如果直接调用底层方法,只会阻塞调用者的线程。

你有两种方法:

  1. 最佳:使用ADO.NET的异步操作。 (这意味着不使用 DataTables/DataAdaptor 但恕我直言,这无论如何都是一个好举动:他们所做的只是将应该在数据库上完成的操作转移到客户端。)

  2. 卸载到另一个线程,但 return 一个 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中的return是一个Task<bool>:调用者需要等待或者同时做一些其他的事情然后得到数据操作的结果。如果调用者只是等待,那么你有两个阻塞的线程。 (C# 5 的 await 不同:调用者也变为异步。)


1 为了避免疑义:这可以看起来像一个正常的,Task<T> returning,异步方法(例如制作使用 TaskCompletionSource<T> 将阻塞从当前线程加载到线程池中的某个线程)。但它仍然是一个阻塞操作:只是阻塞了一个不同的线程。