我有一个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
。
问题:这是否意味着在异步方法中返回的Task不会立即启动?如果我们添加MethodImpl
(带AggressiveInlining
)属性,它会立即启动吗?
我想知道用AggressiveInlining修饰的方法是否对任务调度程序行为有任何影响。
答案 0 :(得分:2)
您的测试是不确定的,因此结果可能会因时间/线程切换/机器负载/核心数量等的变化而有所不同。
例如,如果您将测试更改为:
var nt = NextNum();
Thread.Sleep(1000);
q.Enqueue(10);
然后即使没有-1
,输出也很可能AggressiveInlining
。
问题:这是否意味着在异步方法中返回的Task不会立即启动?如果我们添加MethodImpl(带有AggressiveInlining)属性,它会立即启动吗?
完全没有。 NextNum
返回的任务总是立即开始。但是,Task.Run
排队到线程池的任务可能不会。这就是你看到行为差异的地方。
在原始测试中,Task.Run
排队的任务需要花费足够长的时间才能执行q.Enqueue
。在第二次测试中,Task.Run
排队的任务恰好在q.Enqueue
之前运行。两者都是不确定的,AggressiveInlining
只是改变了时间。
从评论中更新:
我想知道用AggressiveInlining修饰的方法是否对任务调度程序行为有任何影响。
不,它没有。