【问题标题】:how to display/report back progress of Task(Async) actions?如何显示/报告任务(异步)操作的进度?
【发布时间】:2015-06-17 02:11:29
【问题描述】:

我需要将一些进程移至异步。我有 5 个方法需要单独调用并在后台运行,以便用户可以继续他们的工作。

下面的测试代码似乎可以工作......但我无法弄清楚如何返回指示任务已完成的信息(消息)。该类将从单独的窗口窗体中调用,以便显示进度....

来自表格:

    async void BtnGo_Click(object sender, System.EventArgs e)
    {
        label2.Text = @"Starting tasks...";
        var progress = new Progress<string>(
            p =>
            {
                label2.Text = p;
            });
        await TestTask.MyTestMain(progress);
    }

班级:

public static  class TestTask
{
    public static Task MyTestMain(IProgress<string> pProgress)
    {
        return SomethingAsync(pProgress);
    }

    private static async Task SomethingAsync(IProgress<string> pProgress)
    {
        var t1 = SomeThing1(pProgress);
        var t2 = SomeThing2(pProgress);

        await Task.WhenAll(t1, t2);

        if (pProgress != null) pProgress.Report(@"all tasks completed");
    }

    private static async Task SomeThing1()
    {
        await Task.Delay(9000);

        var filename = @"c:\temp\tt1.txt";

        if (File.Exists(filename))
            File.Delete(filename);

        using (TextWriter tw = new StreamWriter(filename))
        {
            await tw.WriteLineAsync(DateTime.Now.ToLongDateString());
        }
        if (pProgress != null) pProgress.Report(@"t1 completed");
    }

    private static async Task SomeThing2()
    {
        await Task.Delay(7000);

        var filename = @"c:\temp\tt2.txt";

        if (File.Exists(filename))
            File.Delete(filename);

        using (TextWriter tw = new StreamWriter(filename))
        {
            await tw.WriteLineAsync(DateTime.Now.ToLongDateString());
        }
        if (pProgress != null) pProgress.Report(@"t2 completed");
    }
}

我想知道每项任务何时完成。任何帮助或指导将不胜感激。

编辑 我编辑了这篇文章以反映我的更改...我仍然无法将进度报告返回到 UI...有什么想法吗?

【问题讨论】:

    标签: c# winforms asynchronous async-await


    【解决方案1】:

    您正在执行 IO 绑定工作,您不需要使用线程池线程。

    转换您的方法以使用 StreamWriter 的异步 API:

    private static async Task FirstThingAsync()
    {
        var filename = @"c:\temp\tt1.txt";
    
        if (File.Exists(filename))
            File.Delete(filename);
    
        using (TextWriter tw = new StreamWriter(filename))
        {
           await tw.WriteLineAsync(DateTime.Now);
        }
    }
    

    第二种方法也是如此,然后您可以同时异步等待它们:

    private static async Task SomethingAsync()
    {
        var firstThing = FirstThingAsync();
        var secondThing = SecondThingAsync();
    
        await Task.WhenAll(firstThing, secondThing);
    }
    

    编辑:

    您永远不会到达您的第一个 Progress.Report 调用,因为当您在 promise 样式的任务上调用 t.Start() 时,您的代码会抛出 InvalidOperationException

    t1.Start();
    await t1;
    
    t2.Start();
    await t2;
    

    两个方法调用返回的任务都是“热任务”,这意味着它的操作已经开始。 Task.Start 上的文档说:

    InvalidOperationException:任务未处于有效状态 开始了。 它可能已经开始、执行或取消,或 它可能是以不支持直接的方式创建的 调度。

    您没有看到该异常的原因是因为您正在吞下它:

    var t = SomethingAsync(pProgress);
    

    当您不等待异步操作时。您的方法调用应如下所示:

    public static Task MyTestMain(IProgress<string> pProgress)
    {
        return SomethingAsync(pProgress);
    }
    
    async void BtnGo_Click(object sender, System.EventArgs e)
    {
        label2.Text = @"Starting tasks...";
        var progress = new Progress<string>(
            p =>
            {
                label2.Text = p;
            });
        await TestTask.MyTestMain(progress);
    }
    

    【讨论】:

    • 但是我如何报告每个任务的进度呢?我想知道每个任务何时完成。这是在一个类中,我需要一些方法来向表单报告并使用每个任务的状态更新 UI。
    • 进度与完成不同。如果您需要进步,请查看IProgress&lt;T&gt;。如果您想了解每个任务的完成情况,可以单独等待它们,而不是使用WhenAll
    • 我只想知道他们什么时候完成...所以我需要为班级创建一个事件并在每次等待后触发该事件...对吗?
    • 您不需要使用事件。 Progress&lt;T&gt; 有一个它调用的回调,您在其中注册一个委托(通过构造函数)。 Progress&lt;T&gt;.OnReport(T value).
    • @YuvalItzchakov Progress 还有一个你可以订阅的事件,而不是构造函数中的委托,或者除了委托之外(这是可选的)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-09-04
    • 1970-01-01
    • 2017-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多