我有一个 ConcurrentQueue
类型的静态字段:
static readonly ConcurrentQueue<int> q = new ConcurrentQueue<int>();
和一个异步方法:
static async Task<int?> NextNum()
{
int? n = await Task.Run<int?>(() =>
{
int i = 0;
if (q.TryDequeue(out i)) return i;
return null;
});
return n;
}
然后我执行这段代码:
var nt = NextNum();
q.Enqueue(10);
nt.Wait();
Console.WriteLine("{0}", nt.Result.HasValue ? nt.Result.Value : -1);
输出为10
。
现在我将 MethodImpl
属性添加到我的异步方法中:
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
static async Task<int?> NextNum()
{
int? n = await Task.Run<int?>(() =>
{
int i = 0;
if (q.TryDequeue(out i)) return i;
return null;
});
return n;
}
当我执行前面提到的代码时,我得到-1
。
问题:这是否意味着在异步方法中返回的任务不会立即启动?如果我们添加 MethodImpl
(带有 AggressiveInlined
)属性,它会立即启动吗?
我想知道用 AggressiveInlined 修饰的方法是否对任务计划程序行为有任何影响。
最佳答案
您的测试是不确定的,因此结果可能会根据计时/线程切换/机器负载/核心数量/等的变化而有所不同。
例如,如果您将测试更改为:
var nt = NextNum();
Thread.Sleep(1000);
q.Enqueue(10);
那么即使没有 AggressiveInlined
,输出也很可能是 -1
。
Question: Does this mean in an async method the returned Task does not start immediately? And if we add MethodImpl (with AggressiveInlining) attribute it starts immediately?
一点也不。 NextNum
返回的任务总是立即开始。但是,通过 Task.Run
排队到线程池的任务可能不会。这就是您看到行为差异的地方。
在您的原始测试中,由 Task.Run
排队的任务恰好花费了足够长的时间,以至于 q.Enqueue
在它之前执行。在第二个测试中,Task.Run
排队的任务恰好在 q.Enqueue
之前运行。两者都是不确定的,AggressiveInlined
只是改变了时间。
评论更新:
I want to know if a method decorated with AggressiveInlining has any effect on task scheduler behavior.
不,事实并非如此。
关于c# - AggressiveInlined 影响 C# 异步方法行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16507270/