如何在PHP脚本(Linux)中计算处理器核心数量?

15

我正在尝试使用pthread进行多线程编程。我使用构造函数创建了一个线程池。第一个参数是工作线程的数量。

$pool = new Pool(8, 'WebWorker');

我希望能够自动检测处理器核心数。就像这样:

$pool = new Pool(get_processor_cores_number(), 'WebWorker');

如何使用PHP实现呢?

6个回答

14

如果服务器是Linux机器,您可以使用以下代码片段:

$ncpu = 1;

if(is_file('/proc/cpuinfo')) {
    $cpuinfo = file_get_contents('/proc/cpuinfo');
    preg_match_all('/^processor/m', $cpuinfo, $matches);
    $ncpu = count($matches[0]);
}

3
这个代码应该更快:$ncpu = substr_count((string)@file_get_contents('/proc/cpuinfo'),"\nprocessor")+1; - 首先,substr_count比preg_match_all更快,我们只打开了一个文件而不是两个,如果文件无法读取,substr_count会返回0并且+1将0转换为1,但当文件可读时,substr_count会跳过第一个处理器,因为它不以换行符开头,而+1也考虑到了这一点 :) - hanshenrik
是的,有很多方法,你甚至可以打开 /sys/devices/system/cpu/online 并读取 online 的 CPU :) - teknoraver
这两个选项都很棒,只要避免使用“shell_exec” :) - Jesse Nickles

7

你可以像这样做,当然你的服务器应该是在Linux系统中:

function get_processor_cores_number() {
    $command = "cat /proc/cpuinfo | grep processor | wc -l";

    return  (int) shell_exec($command);
}

你需要执行一个shell命令,然后将其转换为整数。

PHP没有任何内置功能来实现这个目的吗? - Nick
我不知道有任何原生的PHP函数能够实现这个。 - olibiaz
7
用三个进程和两个管道执行 cat /proc/cpuinfo | grep processor | wc -l 的方法非常冗长。你可以使用一个进程和一个管道来完成同样的操作:grep -c processor /proc/cpuinfo - teknoraver
1
@teknoraver,你可以使用0个管道和0个额外进程完成它:substr_count(file_get_contents("/proc/cpuinfo"),"processor"); - hanshenrik

5

如果有人正在寻找一个简单的函数来获取 WindowsLinux 操作系统下的CPU核心总数,以下是相关内容:

function get_processor_cores_number() {
    if (PHP_OS_FAMILY == 'Windows') {
        $cores = shell_exec('echo %NUMBER_OF_PROCESSORS%');
    } else {
        $cores = shell_exec('nproc');
    }

    return (int) $cores;
}

4

这里有一个暴露sysconf的扩展:krakjoe/sysconf

<?php
$cpusConfigured = sysconf(SYSCONF_NPROCESSORS_CONF);
$cpusOnline     = sysconf(SYSCONF_NPROCESSORS_ONLN);
?>

大多数应用程序只关心配置的数字。

4
避免在获取操作系统简单信息时启动整个新的shell。这样做非常缓慢,而且会占用大量内存,因为您正在为一个简单任务生成整个命令解释器。
以下是可在Linux或Windows上执行而无需启动整个新shell的快速函数:
function get_total_cpu_cores() {
   return (int) ((PHP_OS_FAMILY == 'Windows')?(getenv("NUMBER_OF_PROCESSORS")+0):substr_count(file_get_contents("/proc/cpuinfo"),"processor"));
}

这个方法适用于任何半现代的 Windows 安装(至少从 Windows 95 开始),并且在大多数 Linux 配置下也能运行(假设您有权读取 /proc/cpuinfo)。但是,大多数安装都会使其对世界可读... 所以不应该有任何问题。
需要注意的是,这个方法从技术上讲将显示操作系统看到的可用 CPU 核心。无论是 Windows 还是 Linux,都会将超线程 CPU 线程视为核心,尽管它们不是物理核心。话虽如此,除非您真正需要知道机器上物理核心的数量,否则这个方法仍然可以满足您的需求。如果确实需要了解物理核心数量,则需要进行更深入的处理过程。
希望这能有所帮助!

2
在我的个人库中,我有一个函数来处理这种情况以及其他事情。你可以很容易地修改它,使其使用非标准的PHP函数。
例如,我缓存结果,这样你就可以忽略它了。然后我有一些函数来检查我们是否在Linux、Mac还是Windows上运行。你可以在那里插入类似的检查。为了执行实际的系统特定检查,我使用自己的Process类,它允许重新连接到运行进程以检查状态、输出等。但你可以改变它而只使用exec。
public static function getNumberOfLogicalCPUCores() {
    $numCores = CacheManager::getInstance()->fetch('System_NumberOfLogicalCPUCores');
    if(!$numCores) {
        if(System::isLinux() || System::isMac()) {
            $getNumCoresProcess = new Process("grep -c ^processor /proc/cpuinfo");
            $getNumCoresProcess->executeAndWait();
            $numCores = (int)$getNumCoresProcess->getStdOut();
        }
        else if(System::isWindows()) {
            // Extract system information
            $getNumCoresProcess = new Process("wmic computersystem get NumberOfLogicalProcessors");
            $getNumCoresProcess->executeAndWait();
            $output = $getNumCoresProcess->getStdOut();
            // Lazy way to avoid doing a regular expression since there is only one integer in the output on line 2. 
            // Since line 1 is only text "NumberOfLogicalProcessors" that will equal 0.
            // Thus, 0 + CORE_COUNT, which equals CORE_COUNT, will be retrieved.
            $numCores = array_sum($getNumCoresProcess->getStdOutAsArray());
        }
        else {
            // Assume one core if this is some unkown OS
            $numCores = 1;
        }
        CacheManager::getInstance()->store('System_NumberOfLogicalCPUCores', $numCores);
    }

    return $numCores;
}

对于Linux,return (int)(rtrim(shell_exec('nproc')));应该就足够了。 - hanshenrik
@hanshenrik:这是一个标准命令吗?我可以相信它在所有版本中都可用吗? - inquam
是的,几乎所有的Linux系统都有这个功能,因为它是GNU Coreutils的一部分,我能想到的所有主流Linux发行版都会附带GNU Coreutils(可能不包括Slitaz Linux Floppy,但那是我能想到的唯一例外)。 - hanshenrik
nproc是coreutils的一部分,比grep更容易获得,因为grep不是coreutils的一部分。 - hanshenrik
@hanshenrik:谢谢,太好了。那我就更新我的库,改用这种方法。 - inquam
1
顺便提一下,nrpoc打印核心数,然后打印一个\n(换行符)-我在这里使用了rtrim()来删除换行符,但是cast-to-int无论如何都会忽略换行符,所以如果你喜欢微优化模因,抛弃rtrim()应该可以使它更快,而不改变功能。 - hanshenrik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接