如何在PHP/MySQL应用程序中充分利用多核CPU?
我维护一个定制的类似CMS的应用程序 每当提交文档时,都会执行若干任务,这些任务大致可分为以下几类:如何在PHP/MySQL应用程序中充分利用多核CPU?,php,mysql,multicore,Php,Mysql,Multicore,我维护一个定制的类似CMS的应用程序 每当提交文档时,都会执行若干任务,这些任务大致可分为以下几类: MySQL查询 HTML内容解析 搜索索引更新 类别1包括与文档内容相关的各种MySQL表的更新 类别2包括对MySQL LONGTEXT字段中存储的HTML内容进行解析,以执行一些自动锚定标记转换。我怀疑这项任务花费了大量的计算时间 类别3包括对一个简单的基于MySQL的搜索索引的更新,它只使用与文档相对应的几个字段 所有这些任务都需要完成,才能将文件提交视为完成 承载此应用程序的机器具有双四
您最喜欢的PHP性能评测工具是什么 这可能不是您要寻找的问题的答案,但您寻求的解决方案涉及线程。线程是多核编程所必需的,而线程不是在PHP中实现的 但是,从某种意义上说,您可以通过依赖操作系统的多任务处理能力来伪造PHP中的线程。我建议快速概述一下,制定一个战略,以实现您的需求 死链接:
PHP并不完全面向多线程:正如您已经注意到的,每个页面都由一个PHP进程提供服务——一次只做一件事,包括在数据库服务器上执行SQL查询时“等待” 不幸的是,您对此无能为力:这就是PHP的工作方式
不过,这里有一些想法:
- 首先,您的服务器上一次可能有多个用户,这意味着您将同时提供多个页面,这反过来意味着您将同时运行多个PHP进程和SQL查询。。。这意味着将使用服务器的多个核心。
- 每个PHP进程将在一个内核上运行,以响应一个用户的请求,但Apache有几个并行运行的子进程(每个请求一个,最多几十个或几百个,取决于您的配置)
- MySQL服务器是多线程的,这意味着它可以使用多个不同的内核来响应多个并发请求——即使每个请求不能由多个内核提供服务
而且,如果您认为生成页面花费的时间太长,一个可能的解决方案是将计算分为两组:
- 一方面,生成页面所必须做的事情:对于这些,您所能做的并不多
- 另一方面,有时必须运行的东西,但不一定是立即运行的
- 例如,我在考虑一些统计计算:你希望它们是最新的,但如果它们落后几分钟,通常是可以的
- 电子邮件发送也一样:无论如何,用户在接收/阅读邮件之前需要几分钟,因此无需立即发送邮件
我经常使用的解决方案是某种排队机制:
- web应用程序将内容存储在“待办事项列表”中
- 而且“待办事项列表”由一些通过cronjob频繁运行的批处理取消排队
my.ini
中影响线程性能的典型设置是:
thread_cache_size = 8
如果您有很多新连接,可以通过增加来提高性能。通常,如果您有一个好的线程实现,这不会提供显著的性能改进。但是,如果服务器每秒看到数百个连接,通常应将线程缓存大小设置得足够高,以便大多数新连接使用缓存线程
如果您正在使用,那么您可以使用
thread_concurrency = 8
使应用程序能够向线程系统提示应同时运行的所需线程数
此变量在MySQL 5.6.1中已弃用,并在MySQL 5.7中删除。您应该在看到MySQL配置文件时将其从中删除,除非它们适用于Solaris 8或更早版本
InnoDB::
如果您使用的是has存储引擎,则不会有这样的限制,因为它完全支持线程并发
innodb_thread_concurrency // Recommended 2 * CPUs + number of disks
您还可以查看innodb_read_io_threads
和innodb_write_io_threads
,其中默认值为4
,并且可以将其增加到高达64
$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
// 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
class Sink extends Stackable {
public function run() {
}
}
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');
}
}
}
Document uploaded for processing ..... 5% - Done