在控制台应用程序中使用异步和等待

时间:2018-08-07 09:13:23

标签: c# asynchronous async-await

我有四种方法。

  1. 主要:仅调用预成型方法
  2. 工作:显示“请等待用户”
  3. 花时间:一个需要花费时间才能执行的程序。
  4. 瓶坯:异步调用耗时和工作方法。

以下是我的代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace AsyncObservation
{
    class Program
    {
        static void Main(string[] args)
        {
            preform();
        }
        public static async Task Working()
        {
            Console.WriteLine("Please wait, the program is running");  
        }
        public static async Task Takingtime()
        {
            Console.WriteLine("This Program started");
            Thread.Sleep(1000);
            Console.WriteLine("The Program finished"); 
        }
        public static async void preform()
        {
            Task timer = Takingtime();
            Task wait = Working();
        }
    }
}

最后:我需要展示

This program started. 
Please wait, the program is running 
The program ended.

4 个答案:

答案 0 :(得分:1)

使用Stephen Cleary的Nito.AsyncEx库(可通过Nuget获得)为控制台应用程序提供异步上下文。有关更多详细信息,请参见here

您的申请可以这样写为...

class Program
{
    static int Main(string[] args)
    {
        try
        {
            Console.WriteLine("The application has started");
            AsyncContext.Run(() => LongRunningTaskAsync(args));
            Console.WriteLine("The application has finished");
        }
        catch (Exception ex)
        {
            Console.Error.WriteLine(ex);
            return -1;
        }
    }

    static async Task LongRunningTaskAsync(string[] args)
    {
        Console.WriteLine("The long running task has started");
        // use Task.Delay() rather than Thread.Sleep() to avoid blocking the application
        await Task.Delay(TimeSpan.FromSeconds(10)).ConfigureAwait(false);
        Console.WriteLine("The long running task has finished");  
    }
}

答案 1 :(得分:1)

我在您的程序中看到了几个问题。

  • 尽管Preform既不是异步也不是事件处理程序,但它不会返回任务
  • 在完成预成型之前,将不等待从Preform开始的任务。因此,您永远不知道它们什么时候完成,也不知道结果是什么(例外?)。您甚至可以在程序完成之前结束程序
  • 启动任务后,不能保证它何时运行。您只有在等待任务时才能确保语句已经执行。
  • 使用async-await是确保您的线程四处查看以查看其是否可以做有用的事情的方法,而不是无所事事地等待。 Thread.Sleep忙于等待。如果您想四处看看是否可以做其他事情,请改用await Task.Delay(TimeSpan.FromSeconds(1))

在您的情况下,您必须先等待编写该行的过程,才能确保已写入任何Console行。如果您在等待第一个任务之前就开始了第二个任务,那么您将不知道第一个任务已经进行了多长时间,因此您不确定是否已经将文本写入控制台。

C# 7.1 introduced async Task Main(),因此您可以使用它代替传统的void Main。它使您免于捕获和解释由您开始使流程异步的Task抛出的AggregateException

如果您不想使用async Main,则当然可以使用Task.Run来调用异步函数:

static void Main(string[] args)
{
    try
    {
        var preformTask = Task.Run( () => Preform() );

        DoSomethingElse();    // if needed
        preformTask.Wait();   // wait for preformTask to finish

        Console.WriteLine("Task completed; press any key to finish");
        Console.ReadKey();
    }
    catch (Exception exc) // inclusive ggregateException if one of your Task fails
    {
        ProcessException(exc)
    }
}

static async Task preform()
{
    // To be certain that the Console Line has been written: await
    await Takingtime();

    // if here, you are certain that the Line has been written,
    // or course you have lost parallel processing
    await Working();
}

为了完整性:其他功能

public static async Task Working()
{
    Console.WriteLine("Please wait, the program is running");

    // either return a completed Task, or await for it (there is a difference!
    await Task.CompletedTask;
    // or:
    return Task.CompletedTask; // do not declare async in this case
}

public static async Task Takingtime()
{
    Console.WriteLine("This Program started");

    //Use Task.Delay instead of Sleep
    await Task.Delay(TimeSpan.FromSeconds(1);   // improved readability
    Console.WriteLine("The Program finished");
}

由于Preform中的等待,您可以确定该文本已被编写。但是,您已经失去了一些并行性。

如果您确实希望同时执行这些过程,则不能确定何时写入文本。如果那很重要,那么从应该并行运行的部分(Task.Delay)中分离应该首先运行的部分(写控制台)

static async Task preform()
{
    // Do the things that should be done before parallel tasks are run
    await DoThisFirst();

    // start the Tasks that can work parallel: not sure what statements are executed first
    var taskA = DoTaskA();
    var taskB = DoTaskB();

    // if here, you are free to do something else
    // can't be sure about the status of taskA nor taskB
    DoSomethingElse();

    // if you want to do something after you know that the tasks have completed:
    // await the tasks here:
    await Task.When (new Task[] {taskA, taskB});

    // if here, you are certain that all parallel tasks have completed successfully
    // if desired fetch the return values of the Tasks:
    var returnValueA = taskA.Result;
    var returnValueB = taskB.Result;

    // do all async things of which you needed to be certain that both tasks finished
    // for example:
    await ProcessResults(returnValueA, returnValueB);
}

答案 2 :(得分:0)

在控制台应用程序中,可以在.Wait()方法中使用void Main调用。

在某些需要同步的情况下,.Wait()可能导致死锁(ASP.NET要求进行同步或具有UI线程的XAML / WinForms进行同步),但是这里没有要进行同步的内容。 / p>

static void Main() 
{
     preform.Wait()
}

这将等待异步工作同步完成。您需要该方法同步运行,以便它不会尽早返回。如果您使用async voidawait,该方法将立即返回并退出该方法,awaitMain方法中不起作用。

我还建议使用await Task.Delay(1000);而不是Thread.Sleep(1000);,因为这是规范的async空闲方式。

对于您的代码示例:

class Program
{
    static void Main(string[] args)
    {
        preform().Wait();

        Console.ReadLine();
    }

    public static async Task Working()
    {
        Console.WriteLine("Please wait, the program is running");
    }

    public static async Task Takingtime()
    {
        Console.WriteLine("This Program started");
        await Task.Delay(1000);
        Console.WriteLine("The Program finished");
    }

    public static Task preform()
    {
        return Task.WhenAll(
            Takingtime(),
            Working());
    }
}

答案 3 :(得分:0)

在构造函数中使用preform().Wait()。因此,等待呼叫。然后在preform方法中使用await Takingtime()await Working()。 并且您必须将返回类型更改为Task