简介
PHP 具有完整的多线程支持,您可以通过多种方式充分利用它。已经能够在不同的示例中展示这种多线程能力:
quick Search 将提供额外资源。
类别
1:MySQL 查询
MySQL is fully multi-threaded 并且将使用多个 CPU,前提是操作系统支持它们,如果针对性能进行适当配置,它还将最大限度地利用系统资源。
my.ini 中影响线程性能的典型设置是:
thread_cache_size = 8
如果您有很多新连接,可以增加thread_cache_size 以提高性能。通常,如果您有良好的线程实现,这不会提供显着的性能改进。但是,如果您的服务器每秒看到数百个连接,您通常应该将 thread_cache_size 设置得足够高,以便大多数新连接使用缓存线程
如果您使用的是Solaris,那么您可以使用
thread_concurrency = 8
thread_concurrency 使应用程序能够向线程系统提供有关应同时运行的所需线程数的提示。
此变量自 MySQL 5.6.1 起已弃用,并在 MySQL 5.7 中删除。每当您看到它时,您都应该从 MySQL 配置文件中删除它,除非它们适用于 Solaris 8 或更早版本。
InnoDB::
如果你使用Innodb有存储引擎就没有这样的限制,因为它完全支持线程并发
innodb_thread_concurrency // Recommended 2 * CPUs + number of disks
您还可以查看innodb_read_io_threads 和innodb_write_io_threads,其中默认为4,根据硬件可以增加到64
其他:
还需要查看的其他配置包括 key_buffer_size 、table_open_cache、sort_buffer_size 等。这些都可以带来更好的性能
PHP:
在纯 PHP 中,您可以创建 MySQL Worker,其中每个查询都在单独的 PHP 线程中执行
$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
Here is a Full Working Example of SQLWorker
2:HTML内容解析
我怀疑这项任务花费了大量的计算时间。
如果您已经知道问题,那么通过事件循环、作业队列或使用线程可以更轻松地解决问题。
一次处理一个文档可能是一个非常非常缓慢而痛苦的过程。 @ka 曾经使用 ajax 破解了他的出路来调用多个请求,一些有创意的人只会使用 pcntl_fork 分叉这个过程,但如果你使用的是 windows 那么你就不能利用 pcntl
pThreads 同时支持 windows 和 Unix 系统,你没有这样的限制。就这么简单.. 如果您需要解析 100 个文档?生成 100 个线程...简单
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);
输出
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
使用的类
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');
}
}
}
实验
尝试解析具有105,109 链接但没有线程的8,714 文件,看看需要多长时间。
更好的架构
产生太多线程,这在生产中不是一件聪明的事情。更好的方法是使用Pooling。有一个定义池 Workers 然后 stack 和 Task
性能改进
很好,上面的例子还有待改进。无需等待系统在单个线程中扫描所有文件,您可以使用多个线程扫描我的系统中的文件,然后将数据堆叠到 Workers 进行处理
3:搜索索引更新
第一个答案几乎已经回答了这个问题,但是有很多方法可以提高性能。您是否考虑过基于事件的方法?
介绍活动
@rdlowrey引用1:
这样想吧。想象一下,您需要在 Web 应用程序中同时为 10,000 个连接的客户端提供服务。传统的 thread-per-request 或 process-per-request 服务器不是一种选择,因为无论您的线程多么轻量级,您仍然无法打开 10,000 个线程一次。
@rdlowrey引用2:
另一方面,如果您将所有套接字保存在一个进程中并侦听这些套接字以使其可读或可写,您可以将整个服务器放在一个事件循环中,并仅在有要读取的内容时才对每个套接字进行操作/写。
您为什么不尝试event-driven、non-blocking I/O 方法来解决您的问题。 PHP 有 libevent 来增强你的应用程序。
我知道这个问题全是Multi-Threading,但如果你有时间可以看看Nuclear Reactor written in PHP@igorw
终于
考虑
我认为您应该考虑在某些任务中使用Cache 和Job Queue。你可以很容易地有一条消息说
Document uploaded for processing ..... 5% - Done
然后在后台执行所有浪费时间的任务。请查看Making a large processing job smaller 了解类似案例研究。
分析
分析工具?从Xdebug 到Yslow 的Web 应用程序没有单一的配置文件工具都非常有用。例如。 Xdebug 在线程方面没有用,因为它不受支持
我没有最喜欢的