2017-08-24 79 views
0

我不明白为什么这个测试显示lambda运行一次。我只能看到它可能产生0或10000.但只有一次?理想情况下,我想要执行所有任务,就像Task.WhenAll所建议的工具提示文档一样。任务不能在enumerable.repeat中运行

[Fact] 
    public async Task FireLotsOfQueries() 
    { 
     var counter = 0; 
     var taskList = Enumerable.Repeat(Task.Run(async() => 
     { 
      ++counter; 
      await Task.Delay(1000); 
     }), 10000); 
     await Task.WhenAll(taskList); 
     Assert.Equal(10000, counter); 
    } 

结果:

Xunit.Sdk.EqualException:Assert.Equal()失败预期:10000 实际:1

+2

'++ counter'是不是线程安全的,你需要使用'Interlocked.Increment(ref counter);'如果你想从多个线程更新一个int。 –

+0

@ScottChamberlain幸运的是,代码不能从多个线程访问它。如果代码更改为同时从多个线程访问“counter”,那么是的,这就成了一个问题。 – Servy

回答

6

问题是你没有创建1000任务。您正在创建一个包含1000次相同任务的枚举。试试这个:

public async Task FireLotsOfQueries() 
{ 
    var counter = 0; 
    var taskList = Enumerable.Repeat(0, 10000) 
     .Select(_=> Task.Run(async() => 
     { 
      ++counter; 
      await Task.Delay(1000); 
     })); 
    await Task.WhenAll(taskList); 
    Assert.Equal(10000, counter); 
} 

你一定会需要柜台周围一些锁定为这个版本也失败了,但计数器将是一个价值接近10000

-1

共享在您运行任务counter是真正的问题。 您可以通过使用lock声明,TaskCompletionSource解决这个问题的代码,或Interlocked.Increment接近

要了解为什么counter编译器优化了缓存的结果检查共享 ​​

[Fact] 
public async Task FireLotsOfQueries() 
{ 
    var static volatile counter = 0; 
    var taskList = Enumerable.Repeat(Task.Run(async() => 
    { 
     Interlocked.Increment(ref counter); 
     await Task.Delay(1000); 
    }), 10000); 
    await Task.WhenAll(taskList); 
    Assert.Equal(10000, counter); 
}