3

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

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

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

4

3 回答 3

3

.NET 4 添加了Task Parallel Library,它提供了一种非常简洁的机制来使同步操作异步。

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

这通常看起来像:

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());

您还可以使用它来组合多个异步操作,并在其中任何一个或全部完成时完成,等等。

请注意,以这种方式使用TaskorTask<T>有另一个巨大的优势 - 如果您稍后迁移到 .NET 4.5,您的 API 将按原样工作,无需更改代码,C# 5 中提供了新的 async/await 语言功能。

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

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

于 2012-05-30T23:23:04.487 回答
2

那么在 C# 中有几种方法可以实现这一点

我个人建议您尝试响应式扩展

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);
        }
    }
于 2012-05-30T23:17:55.937 回答
2

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

于 2012-05-30T23:21:01.640 回答