Úvod
PHP má plné Multi-Threading podporu, kterou můžete naplno využít mnoha způsoby. Byli schopni demonstrovat tuto schopnost Multi-Threading na různých příkladech:
- Jak lze v aplikacích PHP používat více vláken
- pcntl spustí stejný kód několikrát, je vyžadována pomoc
- Zlepšení efektivity HTML scraper pomocí pcntl_fork()
rychlé vyhledávání by poskytlo další zdroje.
Kategorie
1:Dotazy MySQL
MySQL je plně funkční vícevláknové a bude využívat více CPU za předpokladu, že je operační systém podporuje. Také by to maximalizovalo systémové prostředky, pokud by byly správně nakonfigurovány pro výkon.
Typické nastavení v my.ini
které ovlivňují výkon vlákna je:
thread_cache_size = 8
thread_cache_size lze zvýšit pro zlepšení výkonu, pokud máte mnoho nových připojení. Pokud máte dobrou implementaci vlákna, toto obvykle neposkytuje výrazné zlepšení výkonu. Pokud však váš server vidí stovky připojení za sekundu, měli byste normálně nastavit thread_cache_size dostatečně vysoko, aby většina nových připojení používala vlákna uložená v mezipaměti
Pokud používáte Solaris pak můžete použít
thread_concurrency = 8
thread_concurrency umožňuje aplikacím poskytnout systému vláken nápovědu o požadovaném počtu vláken, která by měla být spuštěna současně.
Tato proměnná je zastaralá od MySQL 5.6.1 a je odstraněna v MySQL 5.7. Měli byste to odstranit z konfiguračních souborů MySQL, kdykoli to uvidíte, pokud nejsou pro Solaris 8 nebo starší.
InnoDB: :
Tato omezení nemáte, pokud používáte Innodb má modul úložiště, protože plně podporuje souběžnost vláken
innodb_thread_concurrency // Recommended 2 * CPUs + number of disks
Můžete se také podívat na innodb_read_io_threads
a innodb_write_io_threads
kde výchozí je 4
a lze jej zvýšit až na 64
v závislosti na hardwaru
Ostatní:
Mezi další konfigurace, na které se také můžete podívat, patří key_buffer_size
, table_open_cache
, sort_buffer_size
atd., jejichž výsledkem je lepší výkon
PHP:
V čistém PHP můžete vytvořit MySQL Worker, kde se každý dotaz provádí v samostatných PHP vláknech
$sql = new SQLWorker($host, $user, $pass, $db);
$sql->start();
$sql->stack($q1 = new SQLQuery("One long Query"));
$sql->stack($q2 = new SQLQuery("Another long Query"));
$q1->wait();
$q2->wait();
// Do Something Useful
Zde je úplný pracovní příklad SQLWorker
2:Analýza obsahu HTML
Pokud již problém znáte, je snazší jej vyřešit pomocí smyček událostí, fronty úloh nebo pomocí vláken.
Práce na jednom dokumentu jeden po druhém může být velmi, velmi pomalý, bolestivý proces. @ka
jakmile se jednou naboural pomocí ajaxu k volání vícenásobného požadavku, někteří kreativní myslitelé by proces jednoduše rozvětvovali pomocí pcntl_fork
ale pokud používáte windows
pak nemůžete využít výhod pcntl
Pomocí pThreads
podporující jak Windows, tak Unix systémy, nemáte takové omezení. Je to tak snadné jako .. Pokud potřebujete analyzovat 100 dokumentů? Vytvořit 100 vláken ... Jednoduché
Skenování HTML
// Scan my System
$dir = new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS);
$dir = new RecursiveIteratorIterator($dir);
// Allowed Extension
$ext = array(
"html",
"htm"
);
// Threads Array
$ts = array();
// Simple Storage
$s = new Sink();
// Start Timer
$time = microtime(true);
$count = 0;
// Parse All HTML
foreach($dir as $html) {
if ($html->isFile() && in_array($html->getExtension(), $ext)) {
$count ++;
$ts[] = new LinkParser("$html", $s);
}
}
// Wait for all Threads to finish
foreach($ts as $t) {
$t->join();
}
// Put The Output
printf("Total Files:\t\t%s \n", number_format($count, 0));
printf("Total Links:\t\t%s \n", number_format($t = count($s), 0));
printf("Finished:\t\t%0.4f sec \n", $tm = microtime(true) - $time);
printf("AvgSpeed:\t\t%0.4f sec per file\n", $tm / $t);
printf("File P/S:\t\t%d file per sec\n", $count / $tm);
printf("Link P/S:\t\t%d links per sec\n", $t / $tm);
Výstup
Total Files: 8,714
Total Links: 105,109
Finished: 108.3460 sec
AvgSpeed: 0.0010 sec per file
File P/S: 80 file per sec
Link P/S: 907 links per sec
Použitá třída
Sink
class Sink extends Stackable {
public function run() {
}
}
LinkParser
class LinkParser extends Thread {
public function __construct($file, $sink) {
$this->file = $file;
$this->sink = $sink;
$this->start();
}
public function run() {
$dom = new DOMDocument();
@$dom->loadHTML(file_get_contents($this->file));
foreach($dom->getElementsByTagName('a') as $links) {
$this->sink[] = $links->getAttribute('href');
}
}
}
Experiment
Pokus o analýzu 8,714
soubory, které mají 105,109
odkazy bez vláken a uvidíte, jak dlouho by to trvalo.
Lepší architektura
Vytváření příliš mnoha vláken, což není chytrá věc ve výrobě. Lepším přístupem by bylo použít Pooling
. Mít soubor definovaných pracovníků
pak skládat
s Task
Zlepšení výkonu
Dobře, výše uvedený příklad lze ještě vylepšit. Namísto čekání, až systém prohledá všechny soubory v jednom vláknu, můžete použít více vláken k prohledání souborů v mém systému a poté naskládat data do Workers ke zpracování
3:Aktualizace vyhledávacího indexu
To bylo do značné míry zodpovězeno první odpovědí, ale existuje mnoho způsobů, jak zlepšit výkon. Uvažovali jste někdy o přístupu založeném na událostech?
Představujeme událost
@rdlowrey Citace 1:
@rdlowrey Citace 2:
Proč nezkusit experimentovat s event-driven
, non-blocking I/O
přístup k vašemu problému. PHP má libevent
pro nabití vaší aplikace.
Vím, že tato otázka je celá Multi-Threading
ale pokud máte trochu času, můžete se podívat na tento nukleární reaktor napsaný v PHP
od @igorw
Konečně
Zvažování
Myslím, že byste měli zvážit použití Cache
a Job Queue
pro některé z vašich úkolů. Můžete snadno dostat zprávu s nápisem
Document uploaded for processing ..... 5% - Done
Pak provádějte všechny úkoly plýtvání časem na pozadí. Podívejte se prosím na Zmenšení velké úlohy zpracování pro podobnou případovou studii.
Profilování
Nástroj pro profilování? Pro webovou aplikaci z Xdebug neexistuje jediný profilový nástroj na Yslow všechny jsou velmi užitečné. Např. Xdebug není užitečný, pokud jde o vlákna, protože není podporován
Nemám oblíbené