[Laravel] “已达到 10000 次重试仍未找到唯一值”是什么意思?[Faker]

大家好,
我是Mandai,Wild团队负责开发工作的成员。
默认包含的 Faker。Faker 你很可能会使用
的优点在于它支持多种语言,并且可以创建各种类型的测试数据,此外,它还有一个非常有用的方法 `unique`,在创建具有唯一 ID 的多个数据时非常有用。
然而,根据你的使用方式,你可能会遇到类似标题中的错误,你可能不知道它的含义,或者无法解决,只能尝试其他方法……如果发生这种情况,安装 Faker 就显得毫无意义了!因此,这次我想介绍一下如何解决 Faker 中常见的“已达到最大重试次数 10,000 次但未找到唯一值”错误。
错误原因
从错误信息来看,我怀疑代码中某个地方出现了无限循环,但我几乎不知道问题出在哪里。我只知道错误似乎发生在我使用 Faker 的 unique() 方法前后。我不确定
我是否写过任何会导致无限循环的代码。
在合适的时机重置它就能正常工作,但重置当然会导致重复。找到合适的
平衡点需要一段时间的使用,但一旦你弄清楚原因,解决方案自然就会水到渠成……!!
那么,让我们来看一下 Faker 的 unique() 方法的代码。
跟踪 unique() 行为
GitHub 仓库的这一部分是 `unique()` 方法的代码。
它将接收到的变量直接传递给一个名为 `UniqueGenerator` 的类,所以让我们来看看 `UniqueGenerator` 类的代码。
该行为由一个巧妙的魔法方法控制,但本质上,它只是调用了使用 `UniqueGenerator::__call()` 创建对象时接收到的 `Faker\Generator` 对象的一个方法。`while`
循环条件会检查重复项,因此返回值是唯一的。
使用数组键检查重复项看起来比较原始,但原因很容易理解。
抛出 `OverflowException` 时的错误信息包含标题中的文字,原因是此 `do-while` 语句的迭代次数达到了重试次数限制。
如何避免错误
要避免此错误,只有一种方法:更改 unique() 方法的第二个参数的值,并增加循环重试次数。
默认值为 10,000 次重试,但如果您想要 15,000 个值,则肯定会溢出。
增加重试次数:
$factory->define(User::class, function(Faker\Generator $faker) { return [ 'name' => $faker->name(), 'age' => $faker->unique(false, 15000)->numberBetween(1, 80), // 将重试次数改为 15000 ]; });
另一个可能的原因是 Faker\Generator 对象返回的值的变化数量少于 10,000 个。
如上例所示,由于 numberBetween() 只返回 1 到 80 之间的值,因此无法为第 81 个数据点生成唯一值,循环将执行超过重试次数。
虽然姓名和其他随机组合看起来变化丰富,但英文名字只有大约 3,000 个,姓氏只有 473 个,因此变化量相当可观。然而,日语中只有大约 50 个名字和 31 个姓氏,即使是全名也只有大约 1,500 种变化。
即使你想获取 5000 个日语全名,如果只有 1500 种可能的组合,那么使用 `unique()` 函数就毫无意义,你需要考虑其他方法。
例如,似乎可以通过在 `Faker\Generator` 类中添加新的提供程序来实现,但我还没有深入研究,所以希望以后有机会介绍一下。
概括
这次,我研究了一下“已达到最大重试次数 10000 次仍未找到唯一值”的错误,这个错误在使用 Faker 时经常遇到。
事情的起因是我在网上搜索这个错误信息,然后在 StackOverflow 上看到有人说“直接用 reset(true) 就行了!”。我觉得这简直荒谬至极。
我怀疑是不是有什么根本性的误解,所以我调查了一下,但似乎存在不止一个陷阱。
如果您遇到“已达到最大重试次数 10,000 次仍未找到唯一值”的消息,请调查重试次数和获取的虚拟数据量。
就这样。
2
