[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
加载中...
2票,平均分:1.00/12
5,537
X Facebook Hatena书签 口袋

这篇文章的作者

关于作者

万代洋一

我的主要工作是开发社交游戏的Web API,但幸运的是,我也有机会参与其他各种任务,包括市场营销。
我在Beyond中的图像版权采用CC0协议。