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