10MPage.com:2025 年互聯網檔案 - 優化 1000 萬張圖像的平鋪放置
我正在建立 10MPage.com,這是一個雄心勃勃的項目,旨在捕捉 2025 年互聯網的狀態。每個用戶都可以向這個龐大的線上檔案貢獻 64x64 像素的圖像。 新增影像涉及一個多步驟流程:上傳建立待處理的圖塊,在將其放置到網格上之前需要批准。
網格本身是一個資料庫表(稱為tiles
),其中每一行代表一個具有 X 和 Y 座標的 1x1 圖塊。較大的待處理圖塊被分解為多個 1x1 圖塊。 挑戰:有效地將這些圖塊放置到不斷擴展的網格上以容納 1000 萬個條目。
我最初的方法是一個簡單的循環搜尋空位,結果證明是災難性的。 添加數千塊瓷磚只需幾秒鐘;推斷為 1000 萬,預計完成時間需要幾年!
初始方法(低效率):
我的第一次嘗試涉及迭代整個網格以找到可用空間。 網格動態擴展以保持大致正方形的形狀。 這是核心 find()
方法:
<code class="language-php">public function find(int $blockWidth, int $blockHeight): array { // ... (code to determine grid dimensions) ... // Look for a fitting spot for ($y = 0; $y < $newHeight; $y++) { for ($x = 0; $x < $newWidth; $x++) { if ($this->canPlaceBlock($x, $y, $blockWidth, $blockHeight)) { return ['x' => $x, 'y' => $y]; } } } return [0, 0]; } // ... (canPlaceBlock method) ...</code>
這很慢,因為搜尋總是從 (0,0) 開始。 最佳化包括使用單一資料庫查詢的更有效率的canPlaceBlock
方法:
<code class="language-php">public function canPlaceBlock(int $startX, int $startY, int $blockWidth, int $blockHeight): bool { $ys = range($startY, $startY + $blockHeight - 1); $xs = range($startX, $startX + $blockWidth - 1); return !Tile::whereIn('x', $xs)->whereIn('y', $ys)->exists(); }</code>
透過從現有的最小 X 和 Y 座標開始搜尋來進一步嘗試最佳化 find()
也未能顯著提高效能。 將整個網格加載到記憶體中以進行更快的檢查被證明過於佔用記憶體。
解:放置塊
可擴展性的關鍵是採用基於區塊的方法。 我引入了“放置塊”,即 100x100 的圖塊單元,由新的 placement_blocks
資料庫表管理。每個區塊都會追蹤其最小/最大 X 和 Y 座標以及「完整」布林標誌。
這種方法有兩個主要優點:
找出並使用放置塊:
遞歸函數有效地找到可用的放置區塊或根據需要建立新的放置區塊:
<code class="language-php">public function find(array $excludeBlocks = []): PlacementBlock { // ... (code to find or create placement blocks) ... }</code>
place()
方法利用此功能,採用全域鎖定來協調區塊選擇和每區塊鎖定以防止競爭條件:
<code class="language-php">public function place(PendingTile $pendingTile): void { // ... (code to acquire locks and place tiles) ... }</code>
使用最佳化的 canPlaceBlock
方法在放置區塊中加入圖塊。 目前,不支援大於單一放置塊的圖塊。
並發性和可擴充性:
Laravel 作業和 Horizon 管理並發的圖塊放置。 工作人員的數量應等於或小於可用的放置塊數。 這允許輕鬆水平縮放。
這種改進的方法極大地提高了圖塊放置過程的速度和可擴展性,使 10MPage.com 的雄心勃勃的目標可以實現。 立即加入該專案並添加您的貢獻!
以上是用 PHP 填充一百萬個圖像網格以獲取互聯網歷史的詳細內容。更多資訊請關注PHP中文網其他相關文章!