我的代码中出现了一个问题,即Lazy初始化程序的调用频率超出了我的预期。从文档中,我预计使用LazyThreadSafetyMode.ExecutionAndPublication将确保我的初始化函数只被调用一次,例如,如果在定义后访问numbers.Value:
numbers = new Lazy<IEnumerable<int>>(
() => GetNumbers(),
LazyThreadSafetyMode.ExecutionAndPublication
);
但是,我发现如果初始化函数产生结果,初始化函数会被多次调用。我认为这必须延迟执行产量,但我只有模糊的理由。
问题:
在下面的代码中,为什么各个初始化函数执行的次数不同?
void Main()
{
var foo = new foo();
var tasks = new List<Task>();
for (int i = 0; i < 10; ++i) tasks.Add(Task.Run(() => {foreach (var number in foo.Numbers) Debug.WriteLine(number);}));
Task.WaitAll(tasks.ToArray());
tasks.Clear();
for (int i = 0; i < 10; ++i) tasks.Add(Task.Run(() => {foreach (var letter in foo.Letters) Debug.WriteLine(letter);}));
Task.WaitAll(tasks.ToArray());
}
public class foo
{
public IEnumerable<int> Numbers => numbers.Value;
public IEnumerable<char> Letters => letters.Value;
readonly Lazy<IEnumerable<int>> numbers;
readonly Lazy<IEnumerable<char>> letters;
public foo()
{
numbers = new Lazy<IEnumerable<int>>(
() => GetNumbers(),
LazyThreadSafetyMode.ExecutionAndPublication
);
letters = new Lazy<IEnumerable<char>>(
() => GetLetters().ToList(), //ToList enumerates all yielded letters, creating the expected call once behavior
LazyThreadSafetyMode.ExecutionAndPublication
);
}
protected IEnumerable<char> GetLetters()
{
Debug.WriteLine($"{nameof(GetLetters)} Called");
yield return 'a';
yield return 'b';
yield return 'c';
yield break;
}
protected IEnumerable<int> GetNumbers()
{
Debug.WriteLine($"{nameof(GetNumbers)} Called");
yield return 1;
yield return 2;
yield return 3;
yield break;
}
}
答案 0 :(得分:5)
我的代码中出现了一个问题,即Lazy初始化程序的调用频率超出了我的预期。
不,懒惰的初始化程序被调用一次。懒惰的初始化程序是
() => GetNumbers()
,这恰好被称为。
GetNumbers
返回IEnumerable<int>
- 一个整数序列。
当您foreach
该序列时,它会调用GetEnumerator
来获取枚举器,然后在枚举器对象上调用MoveNext
,直到MoveNext
返回false
。
您已经说过要将序列枚举为:
the first time MoveNext is called, do a writeline and produce 1
the second time MoveNext is called, produce 2
the third time MoveNext is called, produce 3
the fourth time MoveNext is called, produce 4
Every subsequent time MoveNext is called, return false
所以每当你枚举序列时,就会发生这种情况。
你能解释一下你预期会发生什么吗?我有兴趣了解为什么人们对计算机程序有错误的信念。
我也不清楚你为什么要使用Lazy
。在需要之前,您通常会使用Lazy
来避免昂贵的工作,但序列已经延迟工作,直到枚举它们为止。