Async always WaitingForActivation

后端 未结 5 1078
夕颜
夕颜 2020-12-02 21:50

I am trying to figure out what the async & await keywords are all about, however the output isn\'t what I\'m expecting.

The console app

相关标签:
5条回答
  • 2020-12-02 22:36

    I overcome this issue with if anybody interested. In myMain method i called my readasync method like

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

    Everything is fine for me now.

    0 讨论(0)
  • 2020-12-02 22:42

    The reason is your result assigned to the returning Task which represents continuation of your method, and you have a different Task in your method which is running, if you directly assign Task like this you will get your expected results:

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

    The output:

    enter image description here

    Consider this for better explanation: You have a Foo method,let's say it Task A, and you have a Task in it,let's say it Task B, Now the running task, is Task B, your Task A awaiting for Task B result.And you assing your result variable to your returning Task which is Task A, because Task B doesn't return a Task, it returns a string. Consider this:

    If you define your result like this:

    Task result = Foo(5);
    

    You won't get any error.But if you define it like this:

    string result = Foo(5);
    

    You will get:

    Cannot implicitly convert type 'System.Threading.Tasks.Task' to 'string'

    But if you add an await keyword:

    string result = await Foo(5);
    

    Again you won't get any error.Because it will wait the result (string) and assign it to your result variable.So for the last thing consider this, if you add two task into your Foo Method:

    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.";
            });
    }
    

    And if you run the application, you will get the same results.(WaitingForActivation) Because now, your Task A is waiting those two tasks.

    0 讨论(0)
  • 2020-12-02 22:49

    this code seems to have address the issue for me. it comes for a streaming class, ergo some of the nomenclature.

    ''' <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
    
    0 讨论(0)
  • 2020-12-02 22:52

    For my answer, it is worth remembering that the TPL (Task-Parallel-Library), Task class and TaskStatus enumeration were introduced prior to the async-await keywords and the async-await keywords were not the original motivation of the TPL.

    In the context of methods marked as async, the resulting Task is not a Task representing the execution of the method, but a Task for the continuation of the method.

    This is only able to make use of a few possible states:

    • Canceled
    • Faulted
    • RanToCompletion
    • WaitingForActivation

    I understand that Runningcould appear to have been a better default than WaitingForActivation, however this could be misleading, as the majority of the time, an async method being executed is not actually running (i.e. it may be await-ing something else). The other option may have been to add a new value to TaskStatus, however this could have been a breaking change for existing applications and libraries.

    All of this is very different to when making use of Task.Run which is a part of the original TPL, this is able to make use of all the possible values of the TaskStatus enumeration.

    If you wish to keep track of the status of an async method, take a look at the IProgress(T) interface, this will allow you to report the ongoing progress. This blog post, Async in 4.5: Enabling Progress and Cancellation in Async APIs will provide further information on the use of the IProgress(T) interface.

    0 讨论(0)
  • 2020-12-02 22:53

    I had the same problem. The answers got me on the right track. So the problem is that functions marked with async don't return a task of the function itself as expected (but another continuation task of the function).

    So its the "await"and "async" keywords that screws thing up. The simplest solution then is simply to remove them. Then it works as expected. As in:

    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.";
        });
    }
    

    Which outputs:

    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.
    
    0 讨论(0)
提交回复
热议问题