繁体   English   中英

C#中的异步方法

[英]Async methods in C#

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

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

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

.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#中将出现新的async / await语言功能5。

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

从一开始,TPL也被设计为与.NET 4的新协作取消模型配合使用。这使您可以使用CancellationTokenSource来取消任何或所有任务。

在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);
        }
    }

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM