使用 symfony 控制器解析大型 JSON 文件
Parsing large JSON file using symfony controller
我有一个很大的 json 文件(不是大小,而是元素)。它有 30000 JSON 个元素,我正在尝试在读取它时从中生成实体。
到目前为止,我已经使用 Guzzle 读取文件,它在崩溃前最终生成了大约 1500 个实体。我觉得我一定是做错了。
这是我的代码:
public function generateEntities(Request $request, $number)
{
$client = new \GuzzleHttp\Client();
$request = new \GuzzleHttp\Psr7\Request('GET', 'http://www.example.com/file.json');
$promise = $client->sendAsync($request)->then(function ($response) {
$batchSize = 20;
$i = 0;
foreach (json_decode($response->getBody()) as $entityItem) {
$entity = new Entity();
$entity->setEntityItem($entityItem->string);
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
if (($i % $batchSize) === 0) {
$em->flush(); // Executes all updates
}
$i++;
}
$em->flush();
});
$promise->wait();
return $this->redirect($this->generateUrl('show_entities'));
}
我从研究中发现我应该经常清除实体管理器,所以我添加了批量大小等以每创建 20 个实体就刷新一次。这确实有帮助,但不足以加载完整的 30000 个文件。
也许我完全错了,应该以不同的方式处理它?
是否有人可以为我指出正确的方向,我很乐意自己解决我只是有点不确定从这里开始。
谢谢!
脚本 运行 内存不足,因为 30000 个实体中的每一个都在内存中进行管理。您需要定期从管理器中分离实体以确保它们 "garbage collected"。在批量刷新块中使用 $em->clear();
以确保内存不会耗尽。有关详细信息,请参阅 Doctrine page on batch operations。
不过请记住,$em->clear()
将从管理器中分离所有实体,而不仅仅是您在此循环中使用的实体。
您可以通过两种方式改进流程:
1) 增加执行控制器动作的时间限制,函数set_time_limit,所以把它作为控制器的第一行:
public function generateEntities(Request $request, $number)
{
set_time_limit(0); // set to zero, no time limit is imposed
2) 释放大量内存是可能的 每次交互将数据刷新到数据库和 detach/free 内存如下:
$em->persist($entity);
$em->flush($entity);
$em->detach($entity);
$em->clear($entity);
unset($entity);
希望对您有所帮助
我有一个很大的 json 文件(不是大小,而是元素)。它有 30000 JSON 个元素,我正在尝试在读取它时从中生成实体。
到目前为止,我已经使用 Guzzle 读取文件,它在崩溃前最终生成了大约 1500 个实体。我觉得我一定是做错了。
这是我的代码:
public function generateEntities(Request $request, $number)
{
$client = new \GuzzleHttp\Client();
$request = new \GuzzleHttp\Psr7\Request('GET', 'http://www.example.com/file.json');
$promise = $client->sendAsync($request)->then(function ($response) {
$batchSize = 20;
$i = 0;
foreach (json_decode($response->getBody()) as $entityItem) {
$entity = new Entity();
$entity->setEntityItem($entityItem->string);
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
if (($i % $batchSize) === 0) {
$em->flush(); // Executes all updates
}
$i++;
}
$em->flush();
});
$promise->wait();
return $this->redirect($this->generateUrl('show_entities'));
}
我从研究中发现我应该经常清除实体管理器,所以我添加了批量大小等以每创建 20 个实体就刷新一次。这确实有帮助,但不足以加载完整的 30000 个文件。
也许我完全错了,应该以不同的方式处理它?
是否有人可以为我指出正确的方向,我很乐意自己解决我只是有点不确定从这里开始。
谢谢!
脚本 运行 内存不足,因为 30000 个实体中的每一个都在内存中进行管理。您需要定期从管理器中分离实体以确保它们 "garbage collected"。在批量刷新块中使用 $em->clear();
以确保内存不会耗尽。有关详细信息,请参阅 Doctrine page on batch operations。
不过请记住,$em->clear()
将从管理器中分离所有实体,而不仅仅是您在此循环中使用的实体。
您可以通过两种方式改进流程:
1) 增加执行控制器动作的时间限制,函数set_time_limit,所以把它作为控制器的第一行:
public function generateEntities(Request $request, $number)
{
set_time_limit(0); // set to zero, no time limit is imposed
2) 释放大量内存是可能的 每次交互将数据刷新到数据库和 detach/free 内存如下:
$em->persist($entity);
$em->flush($entity);
$em->detach($entity);
$em->clear($entity);
unset($entity);
希望对您有所帮助