异步总是WaitingForActivation

Ban*_*San 50 .net c# asynchronous async-await

我试图找出async&await关键字的全部内容,但输出并不是我所期待的.

控制台应用程序如下:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Foo called");
        var result = Foo(5);

        while (result.Status != TaskStatus.RanToCompletion)
        {
            Console.WriteLine("Thread ID: {0}, Status: {1}", Thread.CurrentThread.ManagedThreadId, result.Status);
            Task.Delay(100).Wait();
        }

        Console.WriteLine("Result: {0}", result.Result);
        Console.WriteLine("Finished.");
        Console.ReadKey(true);
    }

    private static async Task<string> Foo(int seconds)
    {
        return await Task.Run(() =>
            {
                for (int i = 0; i < seconds; i++)
                {
                    Console.WriteLine("Thread ID: {0}, second {1}.", Thread.CurrentThread.ManagedThreadId, i);
                    Task.Delay(TimeSpan.FromSeconds(1)).Wait();
                }

                return "Foo Completed.";
            });
    }
}
Run Code Online (Sandbox Code Playgroud)

输出是:

Foo called
Thread ID: 10, Status: WaitingForActivation
Thread ID: 6, second 0.
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 6, second 1.
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 6, second 2.
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 6, second 3.
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 6, second 4.
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Result: Foo Completed.
Finished..
Run Code Online (Sandbox Code Playgroud)

我希望WaitingForActivation在方法启动后看到状态发生变化.

它如何保持这种状态并保持活跃状态​​?

Luk*_*oid 57

对于我的回答,值得记住的是,在async-await关键字之前引入了TPL(任务 - 并行 - 库),Task类和TaskStatus枚举,并且async-await关键字不是TPL的原始动机.

在标记为的方法的上下文中async,结果Task不是Task表示方法的执行,而是表示方法Task的继续.

这只能使用一些可能的状态:

  • 取消
  • 断陷
  • RanToCompletion
  • WaitingForActivation

我理解这Running似乎是一个更好的默认值WaitingForActivation,但这可能会产生误导,因为大多数时候,正在执行的异步方法实际上并没有运行(即它可能是await其他东西).另一个选项可能是添加新值TaskStatus,但这可能是现有应用程序和库的重大变化.

所有这些都与使用Task.Run原始TPL的一部分时非常不同,它能够利用TaskStatus枚举的所有可能值.

如果您希望跟踪异步方法的状态,请查看IProgress(T)界面,这将允许您报告正在进行的进度.此博客文章,4.5中的异步:在异步API中启用进度和取消将提供有关IProgress(T)接口使用的更多信息.


Sel*_*enç 20

原因是你result被分配到Task表示你的方法的继续的返回,并且你的方法中有一个不同的任务正在运行,如果你直接分配这样的任务,你将得到你期望的结果:

var task = Task.Run(() =>
        {
            for (int i = 10; i < 432543543; i++)
            {
                // just for a long job
                double d3 = Math.Sqrt((Math.Pow(i, 5) - Math.Pow(i, 2)) / Math.Sin(i * 8));
            }
           return "Foo Completed.";

        });

        while (task.Status != TaskStatus.RanToCompletion)
        {
            Console.WriteLine("Thread ID: {0}, Status: {1}", Thread.CurrentThread.ManagedThreadId,task.Status);

        }

        Console.WriteLine("Result: {0}", task.Result);
        Console.WriteLine("Finished.");
        Console.ReadKey(true);
Run Code Online (Sandbox Code Playgroud)

output:

在此输入图像描述

考虑这个以获得更好的解释:你有一个Foo方法,让我们说它是任务A,你有一个Task,让我们说它任务B,现在正在运行的任务,是任务B,你的任务A等待任务B的结果.你和你将结果变量分配给返回Task任务A,因为任务B没有返回任务,它返回一个string.考虑一下:

如果您定义结果如下:

Task result = Foo(5);
Run Code Online (Sandbox Code Playgroud)

你不会得到任何错误.但如果你这样定义:

string result = Foo(5);
Run Code Online (Sandbox Code Playgroud)

你会得到:

无法将类型'System.Threading.Tasks.Task'隐式转换为'string'

但是如果你添加一个await关键字:

string result = await Foo(5);
Run Code Online (Sandbox Code Playgroud)

再一次,你不会得到任何错误.因为它会等待结果(字符串)并将其分配给你的结果变量.所以如果你在你的Foo方法中添加两个任务,最后要考虑这个:

private static async Task<string> Foo(int seconds)
{
    await Task.Run(() =>
        {
            for (int i = 0; i < seconds; i++)
            {
                Console.WriteLine("Thread ID: {0}, second {1}.", Thread.CurrentThread.ManagedThreadId, i);
                Task.Delay(TimeSpan.FromSeconds(1)).Wait();
            }

            // in here don't return anything
        });

   return await Task.Run(() =>
        {
            for (int i = 0; i < seconds; i++)
            {
                Console.WriteLine("Thread ID: {0}, second {1}.", Thread.CurrentThread.ManagedThreadId, i);
                Task.Delay(TimeSpan.FromSeconds(1)).Wait();
            }

            return "Foo Completed.";
        });
}
Run Code Online (Sandbox Code Playgroud)

如果你运行应用程序,你将得到相同的结果.(WaitingForActivation)因为现在,你的任务A正在等待这两个任务.