2017-10-02 17 views
5

Tôi có một mảng lớn các mảng kết hợp. Mỗi mảng kết hợp bao gồm khoảng 15 phím các loại khác nhau (chuỗi, số nguyên, float) - ví dụ nhỏ dưới đây:mảng - hết bộ nhớ trong php

$array = [ 
    [ 
     "key1" => "string", 
     "key2" => 10, 
     "key3" => 4.05 
    ],  
    [ 
     "key1" => "string2", 
     "key2" => 20, 
     "key3" => 1.05 
    ],  
    ... 
]; 

Bây giờ tôi muốn để lặp qua mảng này và thêm một số phím như

$map = array_map(function (array $item) {    
     $item['key4'] = 1; 
     $item['key5'] = 1; 
     $item['key6'] = 1; 
     return $item; 
    }, $array); 

Vấn đề: Đối với một mảng có chứa một số lượng lớn các mảng kết hợp, thêm các khóa mới làm cho có giới hạn bộ nhớ đạt được và tập lệnh được chấm dứt. Bạn có giải pháp nào không?

+8

Protip: bắt đầu sử dụng các đối tượng với các lớp và quay lại các đối tượng có cơ sở dữ liệu nếu bạn thực sự có quá nhiều dữ liệu để làm việc mà bạn hết bộ nhớ. Đó là cách lưu trữ hoạt động: bộ nhớ cache cpu, nếu bạn chạy ra khỏi đó, RAM, nếu bạn chạy ra khỏi đó, thời gian để sử dụng hệ thống tập tin. –

+0

Nếu bạn có đủ bộ nhớ, bạn luôn có thể tăng giới hạn bộ nhớ - http://php.net/manual/en/ini.core.php#ini.memory-limit – daker

+0

@ Mike'Pomax'Kamermans Cảm ơn bạn đã trả lời. Bạn có nghĩa là tôi nên sử dụng mảng các đối tượng, đúng không? – Joe

Trả lời

2

Bạn có thể đánh số trang dữ liệu của bạn, đoạn mảng của bạn để làm việc với các phần nhỏ hơn, hoặc thậm chí tăng memory_limit, nhưng chúng ta hãy giả sử rằng bạn có một mảng lớn và không thể làm khác được.

Vì vậy, hãy chơi với một mảng dài 1 000 000 và thử các giải pháp khác nhau. Tôi sẽ đưa mức tiêu thụ bộ nhớ đo thời gian & tính toán từ máy tính xách tay của tôi

giải pháp hiện tại (857MB/640ms)

for ($i=0; $i< 1000000; $i++){ 
    $array[$i] = [ 
     "key" => 'value', 
     "key2" => $i, 
     "key3" => $i/3 
    ]; 
} 

$map = array_map(function (array $item) { 
    $item['key4'] = 1; 
    $item['key5'] = 1; 
    $item['key6'] = 1; 
    return $item; 
}, $array); 

Với đoạn mã này tiêu thụ bộ nhớ trên máy tính xách tay của tôi là 857MB và thời gian tính toán 640ms.

Trong ví dụ của bạn, bạn đang tạo một biến số $map hoàn toàn mới từ số $array. Điều này có nghĩa là bạn đang tạo một bản sao mới của mảng trong bộ nhớ.

Làm việc với references (480Mb/220ms)

$array = []; 
for ($i=0; $i< 1000000; $i++){ 
    $array[$i] = [ 
     "key" => 'value', 
     "key2" => $i, 
     "key3" => $i/3 
    ]; 
} 

foreach ($array as &$item) { 
    $item['key4'] = 1; 
    $item['key5'] = 1; 
    $item['key6'] = 1; 
} 

Với việc sử dụng &$item chúng tôi hỏi PHP để cung cấp cho chúng ta truy cập vào biến bằng cách tham khảo, có nghĩa là chúng ta đang sửa đổi dữ liệu trực tiếp trong bộ nhớ mà không cần tạo một bản sao mới của nó.

Đây là lý do tại sao tập lệnh này tiêu thụ ít bộ nhớ hơn rất nhiều & thời gian tính toán.

Làm việc với các lớp (223MB/95ms)

Theo mui xe, PHP sử dụng cấu trúc dữ liệu C để quản lý dữ liệu trong bộ nhớ. Các lớp học có thể dự đoán được và dễ dàng hơn cho PHP để tối ưu hóa hơn một mảng. Nó được giải thích cũng here

class TestClass { 
    public $key1, $key2, $key3, $key4, $key5, $key6; 
} 

$array = []; 
for ($i=0; $i< 1000000; $i++){ 
    $array[$i] = new TestClass(); 
    $array[$i]->key1 = 'value'; 
    $array[$i]->key2 = $i; 
    $array[$i]->key3 = $i/3; 
} 

foreach ($array as $item) { 
    $item->key4 = 1; 
    $item->key5 = 1; 
    $item->key6 = 1; 
} 

Bạn có thể thấy rằng tiêu thụ bộ nhớ & thời gian để lặp là thấp hơn nhiều. Điều này là do PHP không cần phải sửa đổi cấu trúc của dữ liệu trong bộ nhớ: mọi trường của đối tượng đã sẵn sàng để nhận dữ liệu.Tuy nhiên, hãy cẩn thận nếu bạn thêm một trường không được khai báo trong lớp (ví dụ: $item->newKey = 1: newKey được khai báo động): tối ưu hóa bộ nhớ sẽ không thể thực hiện được nữa và bạn sẽ chuyển sang sử dụng bộ nhớ 620MB & 280ms tính toán)


Nếu bạn muốn đi xa hơn và không sợ đau đầu, hãy xem đến Standard PHP Library (SPL): bạn sẽ tìm thấy rất nhiều các giải pháp cấu trúc dữ liệu được tối ưu hóa (Mảng cố định, vòng lặp & cứ thế ...)

PS: điểm chuẩn được thực hiện với Xdebug bị vô hiệu hóa

-1

Bạn sẽ có thể lưu một số bộ nhớ nếu bạn sử dụng tài liệu tham khảo. Điều này sẽ loại bỏ nhiều bản sao trên các hành động ghi xảy ra nền. Trong một trường hợp thử nghiệm nhỏ. Tôi đã có thể giảm bộ nhớ 30% -40% (tùy thuộc vào phiên bản PHP). Nếu bạn sử dụng PHP5, bạn cũng có thể hưởng lợi từ việc nâng cấp lên PHP7. Rõ ràng là tôi không thể dự đoán liệu một trong hai hoặc cả hai đều tiết kiệm đủ bộ nhớ. Test Case (chỉ cần loại bỏ các /* trước bản đồ hoặc đi bộ):

$cnt=10000; 
for($i=0;$i<$cnt;$i++) { 
    $array[]['key1'] = 1; 
    $array[]['key2'] = 2; 
    $array[]['key3'] = 3; 
} 
/*array_walk($array, function (&$item,$key) {    
    $item['key4'] = 1; 
    $item['key5'] = 1; 
    $item['key6'] = 1; 
}); //memory used PHP7/PHP5: 13 437 720 - 25 924 944 */ 
/*$map = array_map(function (array $item) {    
    $item['key4'] = 1; 
    $item['key5'] = 1; 
    $item['key6'] = 1; 
    return $item; 
}, $array); //memory used PHP7/PHP5: 25 050 360 - 40 850 480*/