C#中的异步方法

时间:2012-05-30 23:13:59

标签: c#

我有几个需要在Windows窗体应用程序的后台运行的进程,因为它们需要花费太多时间而且我不希望冻结用户界面直到它们完全完成,我想有一个指示器来显示每个操作的过程,到目前为止,我有一个表单来显示每个操作的进度,但我的操作同步运行。

所以我的问题是运行这些操作(访问数据库)async的最简单方法是什么?

我忘记了应用程序需要的一个重要功能,用户可以随时取消任何操作。我认为这个要求使应用程序变得很复杂,至少在我目前的技能方面,所以基本上我想说,我需要一个易于理解且易于实现的解决方案。我知道会有好的做法可以遵循但是在这一点上我希望一些代码可以在以后工作我有更多的时间来重构代码

3 个答案:

答案 0 :(得分:3)

.NET 4添加了Task Parallel Library,它为异步操作提供了一种非常干净的机制。

它允许您将同步操作包装到任务中,然后您可以等待,或者使用延续(某些代码在任务完成时执行)。

这通常看起来像:

Task processTask = Task.Factory.StartNew(() => YourProcess(foo, bar));

完成任务后,您有很多选择,包括阻止:

// Do other work, then:
processTask.Wait(); // This blocks until the task is completed

或者,如果你想要一个延续(代码在完成时运行):

processTask.ContinueWith( t => ProcessCompletionMethod());

您也可以使用它来组合多个异步操作,并在完成任何或所有操作时完成,等等。

请注意,以这种方式使用TaskTask<T>还有另一个巨大优势 - 如果您以后迁移到.NET 4.5,那么您的API将按原样运行,不会更改代码异步/等待C#5中的语言功能。

  

我忘记了应用程序需要的一个重要功能,用户可以随时取消任何操作。

TPL也是从它开始时的设计,与.NET 4的新cooperative cancellation model一起很好地工作。这允许你有CancellationTokenSource可以用来取消任何或你的所有任务。

答案 1 :(得分:2)

在C#中,有几种方法可以实现这个目标

我个人建议您尝试使用Reactive Extensions

http://msdn.microsoft.com/en-us/data/gg577609.aspx

你实际上可以这样做:

https://stackoverflow.com/a/10804404/1268570

我为你创建了这个,这很容易,虽然它不是线程安全的,但这将是一个很好的起点

以表格

var a = Observable.Start(() => Thread.Sleep(8000)).StartAsync(CancellationToken.None);
var b = Observable.Start(() => Thread.Sleep(15000)).StartAsync(CancellationToken.None);
var c = Observable.Start(() => Thread.Sleep(3000)).StartAsync(CancellationToken.None);

Manager.Add("a", a.ObserveOn(this).Subscribe(x => MessageBox.Show("a done")));
Manager.Add("b", b.ObserveOn(this).Subscribe(x => MessageBox.Show("b done")));
Manager.Add("c", c.ObserveOn(this).Subscribe(x => MessageBox.Show("c done")));

private void button1_Click(object sender, EventArgs e)
{
    Manager.Cancel("b");
}

经理实用程序

public static class Manager
{
    private static IDictionary<string, IDisposable> runningOperations;

    static Manager()
    {
        runningOperations = new Dictionary<string, IDisposable>();
    }

    public static void Add(string key, IDisposable runningOperation)
    {
        if (runningOperations.ContainsKey(key))
        {
            throw new ArgumentOutOfRangeException("key");
        }

        runningOperations.Add(key, runningOperation);
    }

    public static void Cancel(string key)
    {
        IDisposable value = null;
        if (runningOperations.TryGetValue(key, out value))
        {
            value.Dispose();
            runningOperations.Remove(key);
        }
    }

答案 2 :(得分:2)

如果ORM /数据库API本身没有异步方法,请查看BackgroundWorker Class。它支持取消(CancelAsync / CancellationPending)和进度报告(ReportProgress / ProgressChanged)。