C# 异步始终等待激活

C# 异步始终等待激活,c#,.net,asynchronous,async-await,C#,.net,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)

我试图弄清楚
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.";
            });
    }
}
我希望在方法启动后,状态从
等待激活更改为


它如何保持这种状态并处于活动状态?

原因是您的
结果被分配给返回的
任务
,它代表了您的方法的继续,并且您的运行方法中有一个不同的任务,如果您直接这样分配任务,您将获得预期的结果:

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);
您不会得到任何错误。但如果您这样定义它:

Task result = Foo(5);
string result = Foo(5);
您将获得:

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

但如果您添加了
wait
关键字:

string result = await Foo(5);

再次不会出错。因为它会等待结果(String)并将其赋值给结果变量。因此,在最后一件事中,如果将两个任务添加到您的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.";
        });
}
private静态异步任务Foo(int秒)
{
等待任务。运行(()=>
{
对于(int i=0;i
{
对于(int i=0;i

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

对于我的答案,值得记住的是TPL(),
Task
类和
TaskStatus
枚举是在异步等待关键字之前引入的,异步等待关键字不是TPL的最初动机

在标记为
async
的方法的上下文中,生成的
任务
不是表示方法执行的
任务
,而是表示方法继续的
任务

这只能利用几个可能的状态:

  • 取消
  • 错误的
  • RANTO补全
  • 等待激活
我知道运行<代码>似乎比等待激活<代码>更好,但是这可能会产生误导,因为在大多数情况下,正在执行的异步方法实际上没有运行(即,它可能是等待<代码>等待其他东西)。另一个选项可能是向
任务状态
添加一个新值,但这可能是对现有应用程序和库的突破性更改

所有这些都与使用
任务时非常不同。运行
是原始TPL的一部分,它能够使用
任务状态
枚举的所有可能值


如果希望跟踪异步方法的状态,请查看接口,这将允许您报告正在进行的进度。这篇博文将提供有关使用
IProgress(T)
界面的更多信息。

如果有人感兴趣,我会解决这个问题。 在myMain方法中,我调用了readasync方法,如

Dispatcher.BeginInvoke(new ThreadStart(() => ReadData()));

现在我一切都好了。

我也有同样的问题。这些答案让我走上了正确的道路。所以问题是,标记为async的函数不会像预期的那样返回函数本身的任务(而是函数的另一个延续任务)

所以,是“等待”和“异步”关键字把事情搞砸了。因此,最简单的解决方案就是将其移除。然后它就如预期的那样工作了。例如:

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 Task<string> Foo(int seconds)
{
    return 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.";
    });
}

这段代码似乎为我解决了这个问题。它是为一个流媒体类而来的,因此是一些术语

''' <summary> Reference to the awaiting task. </summary>
''' <value> The awaiting task. </value>
Protected ReadOnly Property AwaitingTask As Threading.Tasks.Task

''' <summary> Reference to the Action task; this task status undergoes changes. </summary>
Protected ReadOnly Property ActionTask As Threading.Tasks.Task

''' <summary> Reference to the cancellation source. </summary>
Protected ReadOnly Property TaskCancellationSource As Threading.CancellationTokenSource

''' <summary> Starts the action task. </summary>
''' <param name="taskAction"> The action to stream the entities, which calls
'''                           <see cref="StreamEvents(Of T)(IEnumerable(Of T), IEnumerable(Of Date), Integer, String)"/>. </param>
''' <returns> The awaiting task. </returns>
Private Async Function AsyncAwaitTask(ByVal taskAction As Action) As Task
    Me._ActionTask = Task.Run(taskAction)
    Await Me.ActionTask '  Task.Run(streamEntitiesAction)
    Try
        Me.ActionTask?.Wait()
        Me.OnStreamTaskEnded(If(Me.ActionTask Is Nothing, TaskStatus.RanToCompletion, Me.ActionTask.Status))
    Catch ex As AggregateException
        Me.OnExceptionOccurred(ex)
    Finally
        Me.TaskCancellationSource.Dispose()
    End Try
End Function

''' <summary> Starts Streaming the events. </summary>
''' <exception cref="InvalidOperationException"> Thrown when the requested operation is invalid. </exception>
''' <param name="bucketKey">            The bucket key. </param>
''' <param name="timeout">              The timeout. </param>
''' <param name="streamEntitiesAction"> The action to stream the entities, which calls
'''                                     <see cref="StreamEvents(Of T)(IEnumerable(Of T), IEnumerable(Of Date), Integer, String)"/>. </param>
Public Overridable Sub StartStreamEvents(ByVal bucketKey As String, ByVal timeout As TimeSpan, ByVal streamEntitiesAction As Action)
    If Me.IsTaskActive Then
        Throw New InvalidOperationException($"Stream task is {Me.ActionTask.Status}")
    Else
        Me._TaskCancellationSource = New Threading.CancellationTokenSource
        Me.TaskCancellationSource.Token.Register(AddressOf Me.StreamTaskCanceled)
        Me.TaskCancellationSource.CancelAfter(timeout)
        ' the action class is created withing the Async/Await function
        Me._AwaitingTask = Me.AsyncAwaitTask(streamEntitiesAction)
    End If
End Sub
对等待的任务的引用。 ''等待的任务。 受保护的只读属性WaitingTask作为Threading.Tasks.Task “行动任务”的引用;此任务状态会发生更改。 受保护的只读属性ActionTask作为Threading.Tasks.Task ''对取消源的引用。 受保护的只读属性TaskCancellationSource作为Threading.CancellationTokenSource ''启动操作任务。 ''流化实体的操作,该操作调用 ''' . ''等待的任务。 专用异步函数AsyncWaitTask(ByVal taskAction作为操作)作为任务 Me.\u ActionTask=Task.Run(taskAction) wait Me.ActionTask的任务。运行(streamEntitiesAction) 尝试 我。行动任务?。等等() Me.onstreamtaskend(如果(Me.ActionTask为Nothing,TaskStatus.RanToCompletion,Me.ActionTask.Status)) 捕获ex作为聚合异常 发生了一个例外(例如) 最后 Me.TaskCancellationSource.Dispose() 结束尝试 端函数 ''开始播放事件。 当请求的操作无效时引发“”。 ''桶钥匙。 ''暂停。 ''流化实体的操作,该操作调用 ''' . 公共可重写子StartStreamEvents(ByVal bucketKey作为字符串,ByVal超时作为时间跨度,ByVal StreamEntities Action作为操作) 如果是我,那么 抛出新的InvalidOperationException($“流任务为{Me.ActionTask.Status}”) 其他的 Me.\u TaskCancellationSource=新建线程。CancellationTokenSource Me.TaskCancellationSource.Token.Register(Me.streamtaskCancelled的地址) Me.TaskCancellationSource.CancelAfter(超时) '操作类是使用Asyn创建的
Foo called
Thread ID: 1, Status: WaitingToRun
Thread ID: 3, second 0.
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 3, second 1.
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 3, second 2.
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 3, second 3.
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 3, second 4.
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Result: Foo Completed.
Finished.
''' <summary> Reference to the awaiting task. </summary>
''' <value> The awaiting task. </value>
Protected ReadOnly Property AwaitingTask As Threading.Tasks.Task

''' <summary> Reference to the Action task; this task status undergoes changes. </summary>
Protected ReadOnly Property ActionTask As Threading.Tasks.Task

''' <summary> Reference to the cancellation source. </summary>
Protected ReadOnly Property TaskCancellationSource As Threading.CancellationTokenSource

''' <summary> Starts the action task. </summary>
''' <param name="taskAction"> The action to stream the entities, which calls
'''                           <see cref="StreamEvents(Of T)(IEnumerable(Of T), IEnumerable(Of Date), Integer, String)"/>. </param>
''' <returns> The awaiting task. </returns>
Private Async Function AsyncAwaitTask(ByVal taskAction As Action) As Task
    Me._ActionTask = Task.Run(taskAction)
    Await Me.ActionTask '  Task.Run(streamEntitiesAction)
    Try
        Me.ActionTask?.Wait()
        Me.OnStreamTaskEnded(If(Me.ActionTask Is Nothing, TaskStatus.RanToCompletion, Me.ActionTask.Status))
    Catch ex As AggregateException
        Me.OnExceptionOccurred(ex)
    Finally
        Me.TaskCancellationSource.Dispose()
    End Try
End Function

''' <summary> Starts Streaming the events. </summary>
''' <exception cref="InvalidOperationException"> Thrown when the requested operation is invalid. </exception>
''' <param name="bucketKey">            The bucket key. </param>
''' <param name="timeout">              The timeout. </param>
''' <param name="streamEntitiesAction"> The action to stream the entities, which calls
'''                                     <see cref="StreamEvents(Of T)(IEnumerable(Of T), IEnumerable(Of Date), Integer, String)"/>. </param>
Public Overridable Sub StartStreamEvents(ByVal bucketKey As String, ByVal timeout As TimeSpan, ByVal streamEntitiesAction As Action)
    If Me.IsTaskActive Then
        Throw New InvalidOperationException($"Stream task is {Me.ActionTask.Status}")
    Else
        Me._TaskCancellationSource = New Threading.CancellationTokenSource
        Me.TaskCancellationSource.Token.Register(AddressOf Me.StreamTaskCanceled)
        Me.TaskCancellationSource.CancelAfter(timeout)
        ' the action class is created withing the Async/Await function
        Me._AwaitingTask = Me.AsyncAwaitTask(streamEntitiesAction)
    End If
End Sub