草庐IT

PHP 输出缓冲区基准测试(与 usleep 一起使用时微时间不准确?)

coder 2024-04-22 原文

我发布了一个可以复制的奇怪行为(至少在 apache2+php5 上)。
我不知道我是否做错了,但让我解释一下我试图实现的目标。

我需要发送大 block 的二进制数据(比如 30)并在最后分析平均 Kbit/s:

我总结每个 block 的输出时间,每个 block 的大小,并在最后执行我的 Kbit/s 计算。

    <?php

// build my binary chunk
$var= '';
$o=10000;
while($o--)
{
    $var.= pack('N', 85985);
}

// get the size, prepare the memory.
$size = strlen($var);
$tt_sent = 0;
$tt_time = 0;

// I send my chunk 30 times
for ($i = 0; $i < 30; $i++)
{
    // start time
    $t = microtime(true);
    echo $var."\n";
    ob_flush();
    flush();
    $e = microtime(true);
    // end time
    // the difference should reprenent what it takes to the server to 
    // transmit chunk to client right ?

    // add this chuck bench to the total
    $tt_time += round($e-$t,4);
    $tt_sent += $size;
}

// total result
echo "\n total: ".(($tt_sent*8)/($tt_time)/1024)."\n";

?>

在上面的这个例子中,它到目前为止工作正常(在本地主机上,它通过不同的测试从​​ 7000 到 10000 Kbit/s 振荡)。

现在,假设我想对传输进行整形,因为我知道客户端将有足够的数据 block 来处理一秒钟。

我决定使用 usleep(1000000) 来标记 block 传输之间的暂停。
    <?php

// build my binary chunk
$var= '';
$o=10000;
while($o--)
{
    $var.= pack('N', 85985);
}

// get the size, prepare the memory.
$size = strlen($var);
$tt_sent = 0;
$tt_time = 0;

// I send my chunk 30 times
for ($i = 0; $i < 30; $i++)
{
    // start time
    $t = microtime(true);
    echo $var."\n";
    ob_flush();
    flush();
    $e = microtime(true);
    // end time
    // the difference should reprenent what it takes to the server to 
    // transmit chunk to client right ?

    // add this chuck bench to the total
    $tt_time += round($e-$t,4);
    $tt_sent += $size;

    usleep(1000000);
}

// total result
echo "\n total: ".(($tt_sent*8)/($tt_time)/1024)."\n";

?>

在最后一个例子中,我不知道为什么,计算出的带宽可以从 72000 Kbit/s 跳到 1,200,000,这是完全不准确的/无关紧要的。
部分问题在于,每次发送一个 block 时(在第一次使用 sleep 之后),输出我的 block 所测量的时间都低得离谱。

我做错了什么?缓冲区输出是否不同步?

最佳答案

我不确定这些测试的确定性,但我觉得这很有趣。在我的盒子上,我平均约为 170000 kb/s .从一个联网的盒子,这个数字上升到大约 280000 kb/s .我想我们必须假设 microtime(true) 是相当准确的,即使我读到它依赖于操作系统。您使用的是基于 Linux 的系统吗?真正的问题是我们如何计算 1 秒内传输的千比特?我尝试预测 1 秒内可以发送多少 block ,然后存储计算的 Kb/s 以在最后进行平均。我在flush() 之前添加了sleep(1),这导致预期的kb/s 为负。

感觉有些不对劲,我很想知道您是否改进了测试方法。祝你好运!

<?php
// build my binary chunk
$var= '';
$o=10000;

//Alternative to get actual bytes
$m1 = memory_get_usage();
while($o--)
{
    $var.= pack('N', 85985);
}
$m2 = memory_get_usage();

//Your size estimate
$size = strlen($var);

//Calculate alternative bytes
$bytes = ($m2 - $m1); //40108

//Convert to Kilobytes 1 Kilobyte = 1024 bytes
$kilobytes = $size/1024;

//Convert to Kilobits 1 byte = 8 bits
$kilobits = $kilobytes * 8;

//Display our data for the record
echo "<pre>size: $size</pre>";
echo "<pre>bytes: $bytes</pre>";
echo "<pre>kilobytes: $kilobytes</pre>";
echo "<pre>kilobits: $kilobits</pre>";
echo "<hr />";

//The test count
$count = 100;

//Initialize total kb/s variable
$total = 0;

for ($i = 0; $i < $count; $i++)
{
    // Start Time
    $start = microtime(true);

    // Utilize html comment to prevent browser from parsing
    echo "<!-- $var -->";

    // End Time
    $end = microtime(true);

    // Seconds it took to flush binary chunk
    $seconds = $end - $start;

    // Calculate how many chunks we can send in 1 second
    $chunks = (1/$seconds);

    // Calculate the kilobits per second
    $kbs = $chunks * $kilobits;

    // Store the kbs and we'll average all of them out of the loop
    $total += $kbs;
}

//Process the average (data generation) kilobits per second
$average = $total/$count;

echo "<h4>Average kbit/s: $average</h4>";

分析

即使我在测试中得出了一些任意值,它仍然是一个可以测量的值。使用联网计算机可以深入了解实际情况。我原以为 localhost 机器的值(value)会比联网机器的值(value)高,但测试在很大程度上证明了并非如此。在本地主机上时,我们必须同时发送和接收原始二进制数据。这当然表明两个线程正在共享 cpu 周期,因此在同一台机器上的浏览器中进行测试时,假定的 kb/s 值实际上更低。因此,我们实际上是在测量 CPU 周期,并且当服务器被允许作为服务器时,我们会获得更高的值。

当您将测试计数增加到 1000 时,一些有趣的事情开始出现。首先不要让浏览器解析数据。尝试在如此高的测试用例中呈现原始数据需要大量 CPU。我们可以通过系统监视器和任务管理器手动观察正在发生的事情。在我的情况下,本地是 linux 服务器,网络盒是 xp。您可以通过这种方式获得一些真正的 kb/s 速度,很明显我们主要使用 cpu 和网络接口(interface)动态提供数据。服务器不会复制数据,因此无论我们设置多高的测试计数,我们只需要 40 KB 的内存空间。因此,40 KB 可以在 1000 个测试用例中动态生成 40 MB,在 10000 个用例中可以动态生成 400mb。

在多次运行测试用例 10000 次后,我在 xp 中使用虚拟内存将 firefox 崩溃到低错误。 linux 服务器上的系统监视器显示 cpu 和网络出现了一些可以理解的峰值,但总体而言,它确实很快地推出了大量数据,并且有足够的空闲空间。在 linux 上运行 10000 个案例几次实际上会启动交换驱动器并固定服务器 CPU 周期。最有趣的事实是,我上面获得的值仅在我在 Firefox 中接收并在本地测试时在 apache 中传输时发生变化。我几乎锁定了 xp 盒子,但我的 ~280000 kb/s 网络值在打印输出时没有改变。

结论:

我们上面得到的 kb/s 值几乎没有用,除非证明它没有用。然而,测试本身显示了一些有趣的事情。在高测试案例中,我相信我实际上可以看到服务器和客户端都在进行一些物理缓冲。我们的测试脚本实际上将数据转储到 apache 并且它被释放以继续其工作。 Apache 处理传输的细节。这实际上很高兴知道,但证明我们无法以这种方式测量从服务器到浏览器的实际传输速率。我们可以衡量我们的服务器数据生成率,我想这在某种程度上是否有意义。你猜怎么着!冲洗实际上减慢了速度。 冲水有罚单 .在这种情况下,没有理由删除flush()实际上加快了我们的数据生成速度。由于我们不处理网络,我们上面的值实际上更有意义,以千字节为单位。任何方式都没用,所以我不会改变。

关于PHP 输出缓冲区基准测试(与 usleep 一起使用时微时间不准确?),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5730996/

有关PHP 输出缓冲区基准测试(与 usleep 一起使用时微时间不准确?)的更多相关文章

  1. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  2. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

    为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

  3. ruby - 通过 erb 模板输出 ruby​​ 数组 - 2

    我正在使用puppet为ruby​​程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby​​不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这

  4. ruby - 如何进行排列以有效地定制输出 - 2

    这是一道面试题,我没有答对,但还是很好奇怎么解。你有N个人的大家庭,分别是1,2,3,...,N岁。你想给你的大家庭拍张照片。所有的家庭成员都排成一排。“我是家里的friend,建议家庭成员安排如下:”1岁的家庭成员坐在这一排的最左边。每两个坐在一起的家庭成员的年龄相差不得超过2岁。输入:整数N,1≤N≤55。输出:摄影师可以拍摄的照片数量。示例->输入:4,输出:4符合条件的数组:[1,2,3,4][1,2,4,3][1,3,2,4][1,3,4,2]另一个例子:输入:5输出:6符合条件的数组:[1,2,3,4,5][1,2,3,5,4][1,2,4,3,5][1,2,4,5,3][

  5. ruby-on-rails - 如果我将 ruby​​ 版本 2.5.1 与 rails 版本 2.3.18 一起使用会怎样? - 2

    如果我使用ruby​​版本2.5.1和Rails版本2.3.18会怎样?我有基于rails2.3.18和ruby​​1.9.2p320构建的rails应用程序,我只想升级ruby的版本,而不是rails,这可能吗?我必须面对哪些挑战? 最佳答案 GitHub维护apublicfork它有针对旧Rails版本的分支,有各种变化,它们一直在运行。有一段时间,他们在较新的Ruby版本上运行较旧的Rails版本,而不是最初支持的版本,因此您可能会发现一些关于需要向后移植的有用提示。不过,他们现在已经有几年没有使用2.3了,所以充其量只能让更

  6. ruby - 将 spawn() 的标准输出/标准错误重定向到 Ruby 中的字符串 - 2

    我想使用spawn(针对多个并发子进程)在Ruby中执行一个外部进程,并将标准输出或标准错误收集到一个字符串中,其方式类似于使用Python的子进程Popen.communicate()可以完成的操作。我尝试将:out/:err重定向到一个新的StringIO对象,但这会生成一个ArgumentError,并且临时重新定义$stdxxx会混淆子进程的输出。 最佳答案 如果你不喜欢popen,这是我的方法:r,w=IO.pipepid=Process.spawn(command,:out=>w,:err=>[:child,:out])

  7. ruby - Ruby 是否使用 $stdout 来写入 puts 和 return 的输出? - 2

    我想知道Ruby用来在命令行打印这些东西的输出流:irb(main):001:0>a="test"=>"test"irb(main):002:0>putsatest=>nilirb(main):003:0>a=>"test"$stdout是否用于irb(main):002:0>和irb(main):003:0>?而且,在这两次调用之间,$stdout的值是否有任何变化?另外,有人能告诉我打印/写入这些内容的Ruby源代码吗? 最佳答案 是的。而且很容易向自己测试/证明。在命令行试试这个:ruby-e'puts"foo"'>test.

  8. ruby-on-rails - 无法在 Rails 助手中捕获 block 的输出 - 2

    我在使用自定义RailsFormBuilder时遇到了问题,从昨天晚上开始我就发疯了。基本上我想对我的构建器方法之一有一个可选block,以便我可以在我的主要content_tag中显示其他内容。:defform_field(method,&block)content_tag(:div,class:'field')doconcatlabel(method,"Label#{method}")concattext_field(method)capture(&block)ifblock_given?endend当我在我的一个Slim模板中调用该方法时,如下所示:=f.form_field:e

  9. ruby-on-rails - 如何让 datamapper 与 postgresql 数据库一起工作? - 2

    我已经找到了几个使用datamapper的示例,并且能够让它们正常工作。不过,所有这些示例都是针对sqlite数据库的。我正在尝试将数据映射器与postgresql一起使用。我将datamapper中的调用从sqlite3更改为postgres,并且我已经安装了dm-postgres-adapter。但它仍然不起作用。我还需要做什么? 最佳答案 与SQLite不同,PostgreSQL不将数据库存储在单个文件中。在你拥有createdyourdatabase之后,尝试这样的事情:DataMapper.setup:default,{:

  10. ruby-on-rails - 连接字符串时如何在 <%=%> block 内输出 html_safe? - 2

    考虑一下:现在这些情况:#output:http://domain.com/?foo=1&bar=2#output:http://domain.com/?foo=1&bar=2#output:http://domain.com/?foo=1&bar=2#output:http://domain.com/?foo=1&bar=2我需要用其他字符串输出URL。我如何保证&符号不会被转义?由于我无法控制的原因,我无法发送&。求助!把我的头发拉到这里:\编辑:为了澄清,我实际上有一个像这样的数组:@images=[{:id=>"fooid",:url=>"http://

随机推荐