【问题标题】:AggressiveInlining Affects C# async Methods BehaviourAggressiveInlining 影响 C# 异步方法行为
【发布时间】:2013-05-13 02:10:17
【问题描述】:

我有一个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(带有AggressiveInlining)属性,它会立即启动吗?

我想知道用 AggressiveInlining 修饰的方法是否对任务调度程序的行为有任何影响。

【问题讨论】:

    标签: c# task-parallel-library async-await c#-5.0 methodimplattribute


    【解决方案1】:

    您的测试是不确定的,因此结果可能会根据时间/线程切换/机器负载/内核数量/等的变化而有所不同。

    例如,如果您将测试更改为:

    var nt = NextNum();
    Thread.Sleep(1000);
    q.Enqueue(10);
    

    那么即使没有AggressiveInlining,输出也很可能是-1

    问题:这是否意味着在异步方法中返回的任务不会立即启动?如果我们添加 MethodImpl(带有 AggressiveInlining)属性,它会立即启动吗?

    一点也不。 NextNum 返回的任务总是立即开始。但是,Task.Run 排队到线程池的任务可能不会。这就是您看到行为差异的地方。

    在您的原始测试中,Task.Run 排队的任务恰好花费了足够长的时间,以至于q.Enqueue 在它之前被执行。在您的第二个测试中,Task.Run 排队的任务恰好在q.Enqueue 之前运行。两者都是不确定的,AggressiveInlining 只是改变了时间。

    来自 cmets 的更新:

    我想知道用 AggressiveInlining 修饰的方法是否对任务调度程序的行为有任何影响。

    不,它没有。

    【讨论】:

    • 如果我的机器没有做任何特别的事情(并且应用程序只是进行测试),那么这个测试是确定性的,并且总是提供我在帖子中提到的结果。我已经测试并使用了这段代码一段时间。我想知道用 AggressiveInlining 修饰的方法是否对任务调度程序的行为有任何影响。
    • @kaveh-Shahbazian,这是在调试模式 - 输出似乎是“确定性的”,总是输出 10。但在发布模式 (Ctrl+F5) 下,您的代码主要输出 -1,有时很少输出 10。原因很明显 - 调试基础设施安装需要更多时间才能在出队之前允许入队
    • @KavehShahbazian:如果您可以将任何类型的Thread.Sleep 添加到任何位置并使其更改结果,那么测试不是确定性的。关于AggressiveInlining,答案是“不,它对任务调度程序的行为没有影响。”
    • @StephenCleary 不管我对“确定性”的理解是什么(我认为只要初始状态相同,我们就应该得到相同的输出)所以这里有一点分歧;请修改答案并在任务计划程序中添加您的评论,以便我将其标记为答案。谢谢;
    猜你喜欢
    • 2017-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-09
    相关资源
    最近更新 更多