PHP kehabisan memori dengan CDataProviderIterator (Yii)

Saya mengalami masalah kehabisan memori dengan skrip PHP saya pada kerangka Yii. Saya sudah mencoba melakukan sedikit debugging. Saya menggunakan CDataProviderIterator karena dokumentasi Yii menyatakan hal ini:

Misalnya, kode berikut akan mengulangi semua pengguna terdaftar (Pengguna kelas rekaman aktif) tanpa kehabisan memori, bahkan jika ada jutaan pengguna di database.

Kode ini mengulangi sekitar 1,5 juta catatan dan kehabisan memori dalam upayanya. Saya mencari bantuan apa pun mengapa ia bisa melakukan ini. Terima kasih!

public function foo($model, $relations) {
    $dataProvider = new CActiveDataProvider($model, array('criteria' => $model->dbCriteria));
    $iterator = new CDataProviderIterator($dataProvider, 200);
    $this->modelsToArray($iterator, $relations, $model_as_array = array());
}

public function modelsToArray($model, $relations, $model_as_array = array()) {
    $preparedRelations = $this->prepareRelations($relations);
    if (is_null($model))
    {
        return array();
    }
    $model_as_array = array();
    if (get_class($model) === 'CDataProviderIterator') {
        foreach ($model as $row) {
            $model_as_array[] = $this->modelsToArrayHelper($preparedRelations, $row);
        }   
    }
    else {
        $model_as_array[] = $this->modelsToArrayHelper($preparedRelations, $model);
    }

    return $model_as_array;
}

private function modelsToArrayHelper($relations, $listOfModels) {
    $listOfArrayModels = array();

    if(!is_array($listOfModels)){
        return $this->modelToArrayHelper($listOfModels, $relations);
    }
    foreach ($listOfModels as $index => $model)
    {
        $listOfArrayModels[$index] = $this->modelToArrayHelper($model, $relations);
    }
    return $listOfArrayModels;
}

private function modelToArrayHelper($model, $relations){
    $model_as_array = $this->processAttributes($model);
    foreach ($relations as $relationIndex => $relation)
    {
        $relationName = is_string($relationIndex) ? $relationIndex : $relation;
        if(empty($model->$relationName)) 
            continue;
        if ($model->relations()[$relationName][0] != CActiveRecord::STAT)
        {
            $subRelations = is_array($relation) ? $relation : array();
            $model_as_array[$relationName] = $this->modelsToArrayHelper($subRelations, $model->$relationName);
        }
        else
        {
            $model_as_array[$relationName] = $model->$relationName;
        }
    }

    return $model_as_array;
}

person Sloganho    schedule 15.04.2016    source sumber
comment
perbaikan cepat ketika saya mencoba membuat ulang ini_set('memory_limit', '-1');   -  person Midhun    schedule 15.04.2016
comment
Anda mengonversi $iterator menjadi array sehingga membutuhkan lebih banyak ram! menurut saya itulah yang menyebabkan masalah ini   -  person Midhun    schedule 15.04.2016
comment
apakah kamu menyelesaikan ini?   -  person Midhun    schedule 16.04.2016


Jawaban (1)


saya yakin Anda mencoba mengonversi CDataProviderIterator ke array Php. jadi untuk menempatkan array Anda membutuhkan lebih banyak memori

ini_set('memory_limit', '-1');

ini mengatur penggunaan ram ke penggunaan maksimal

ini_set('memory_limit', '512M');

ini mengatur penggunaan ram menjadi 512 Mb

Bisakah Anda membuat kode seperti ini hanya untuk memastikan Anda tidak menggunakan terlalu banyak ram

public function foo($model, $relations) {
    $dataProvider = new CActiveDataProvider($model, array('criteria' => $model->dbCriteria));
    $iterator = new CDataProviderIterator($dataProvider, 200);
    $preparedRelations = $this->prepareRelations($relations);
    foreach ($iterator as $row) {
           print_r ($this->modelsToArrayHelper($preparedRelations, $row));
    }   
}

Dan

person Midhun    schedule 15.04.2016
comment
Jadi saya tidak mencoba mengubah CDataProviderIterator menjadi array php. Saya mengonversi setiap catatan yang diulang ke dalam array. Pada kenyataannya, ini seharusnya menghemat memori karena cara CDataProviderIterator tidak menyimpan semua objek di memori. Dalam kasus saya, ini hanya akan menyimpan 200 objek model dalam memori sekaligus dan kemudian akan menghapusnya. Saya mencoba solusi Anda dan sekarang saya tidak mendapat tanggapan balik. Pertanyaan utama saya adalah mengapa ini memakan begitu banyak memori padahal kenyataannya, ini seharusnya memakan lebih sedikit memori berdasarkan klaim dalam dokumentasi. - person Sloganho; 15.04.2016
comment
Karena sepertinya Anda mencoba menyimpan 1,5 juta array di dalam $model_as_array - person georaldc; 15.04.2016
comment
ya saya bisa melihatnya tetapi apa yang Anda lakukan dengan $model_as_array; - person Midhun; 15.04.2016
comment
Saya mencoba menyimpan 1,5 juta objek di dalam array $model_as_array. Apa yang saya lakukan dengan $model_as_array adalah mengonversinya menjadi JSON dan mengirimkannya kembali ke klien. Menetapkan batas memori seperti itu sepertinya bukan praktik yang baik bagi saya. Saya tetap mencobanya dan tidak berhasil. Saya menemukan solusi untuk hanya mengonversi array ke JSON saat saya melanjutkan, memanggil objek yang tidak disetel setelah saya mengonversinya untuk menghemat memori. Ini berfungsi dan benar-benar menghemat memori, bukan hanya mengubah batas memori. Terima kasih atas bantuan Anda. - person Sloganho; 16.04.2016
comment
Bagus, bisakah Anda membagikan kode contoh untuk solusi Anda sehingga komunitas juga dapat memperoleh manfaat. Silakan tambahkan sebagai jawaban - person Midhun; 16.04.2016