使用 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);

希望对您有所帮助