2017-10-23 20 views
1

私のアプリケーションには、ユーザーが要求するたびに膨大な量のデータを処理する必要があります。スクリプトはもともとforeachループで編成されていましたが、そのためPHPは毎回タイムアウトしました。私はRedisのキューを使用して移動しましたが、その後私はメモリの問題を抱えていました。スクリプト/キューのメモリが不足しています

mmap() failed: [12] Cannot allocate memory 

PHP Fatal error: Out of memory (allocated 79691776) (tried to allocate 134217728 bytes) 

今、私は一つのプロセスだけを持つようにキューを設定しました。それはうまくいくが、しばらく後に私は再びメモリエラーを取得し始めます。これは私がテストしているところです。ユーザーがそれを使い始めたら、それはちょうど転倒します。

スクリプトを1024MBに割り当てるのは、1回だけ使用しないとメモリが不足するためです。私は、スクリプトを実行してメモリを解放するたびに何かできることがあるかどうか疑問に思っています。変数を設定しないようにしますか?私はこれがどのように役立つかを見ることができません。スクリプトが終了し、キューの作業者によって最初から再び実行されるのを見ています。

私が2GB RAM

で浮浪者のマシン(ホームステッド)を使用していUPDATE:

バックテストでは、我々は、ディスパッチャを実行したときに始まり、10回のリーグと10年を介して実行されます。

public function init($authUserId, $systemId, $token, $league, $year) 
    { 
//  ini_set('memory_limit', -1); 
     ini_set('max_execution_time', 300); //300 seconds = 5 minutes 
     ini_set('memory_limit', '1024M'); // or you could use 1G 
     $this->authUserId = $authUserId; 
     $this->systemId = $systemId; 
     $this->token = $token; 
include(storage_path("app/matches/{$league->key}/{$year}.php")); 
     $this->leagueResults[$league->key][$year] = collect($this->leagueResults[$league->key][$year]); 
//Loops through the data - saves to new array 
fwrite($file, serialize($backtest)); 
:それは非常に多くのことを行いますので、

以下
class BacktestJob implements ShouldQueue 
{ 
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; 

    private $token; 
    private $league; 
    private $year; 
    private $authUserId; 
    private $systemId; 

    public $timeout = 10000; 


    /** 
    * Create a new job instance. 
    * 
    * @return void 
    */ 
    public function __construct($authUserId, $systemId, $token, $league, $year) 
    { 
     $this->token = $token; 
     $this->league = $league; 
     $this->year = $year; 
     $this->authUserId = $authUserId; 
     $this->systemId = $systemId; 
    } 

    /** 
    * Execute the job. 
    * 
    * @return void 
    */ 
    public function handle() 
    { 
     $backtest = new Backtest; 
     $backtest->init($this->authUserId, $this->systemId, $this->token, $this->league, $this->year); 
    } 
} 

は、メインスクリプトのストリップダウンバージョンです:

ディスパッチャクラス:

class Dispatcher 
{ 
    use Attributes; 
    use DataRetriever; 
    public function runBacktest($token) 
    { 
     $authUserId = Auth::user()->id; 
     $system = System::where('token', $token)->first(); 
     $this->getSystem($authUserId, $system->id); 
     foreach ($this->leagues as $league) { 
      foreach ($this->years as $year) { 
       BacktestJob::dispatch($authUserId, $system->id, $token, $league, $year); 
      } 
     } 
    } 
} 

ディスパッチャはジョブを実行します

元々、データは50MBのjsonファイルから取得されました。 jsonファイルをハードコードされたPHP配列(ファイルサイズ100MB)に置き換えました。私は新しいファイルが大きいことを知っていますが、json_decodeが処理を高速化しますが、私は行っていないと仮定しました。

私もスクリプトの最後にdb insertを削除しましたが、私の人生を楽にしてくれるので、私はそれを保持することをお勧めします。

+0

PHPスクリプトが終了すると、メモリーは自動的に割り当てが解除されます。 – bassxzero

+0

ここでは、1024MBではなく128MBの制限(134217728バイト)を示しています。どのようなコードを提示することなく、私はどのように助けることができるのか分かりません。 – Devon

+0

ありがとう@bassxzero – user1894292

答えて

0

私はデータファイルを分割して問題を解決しました。私は元のデータファイルへの完全なアクセス権を持っており、すべての要求に対してすべてのデータを必要としないので、私はそれを約50個の小さなファイルに分割しました。

パフォーマンスが向上したことに私は驚きました。 30秒以上でタイムアウトしてから2秒未満になりました。要求の大部分は1秒未満で完了しました。

関連する問題