【问题标题】:How to tell at runtime if my process is CPU bound or I/O bound如何在运行时判断我的进程是 CPU 绑定还是 I/O 绑定
【发布时间】:2012-11-26 21:21:44
【问题描述】:

我有一个程序通过 TCP 链接发送数据。我正在使用异步读写磁盘和网络。如果我在中间放一个DeflateStream(所以我在写入网络链接之前压缩,当我收到数据并将其写入磁盘时解压缩)我在压缩方面受CPU限制。这导致我的最大传输速率约为300 KB/s。但是,如果我删除压缩步骤,我现在将 I/O 绑定到磁盘,并且得到40,000 KB/s 的传输速率。

在严格的 LAN 条件下,我的 I/O 上限将始终超过 300 KB/s,但是如果我的程序在 Internet 上运行,我的网络 IO 限制很可能低于 300 KB/s。

我想检测我是否受 I/O 限制并且我的网络/磁盘链接是限制因素,或者我是否受 CPU 限制并且压缩行为是最让我慢下来的原因。如何检测我的程序在运行时是否受到 CPU 或 I/O 的限制,以便切换协议并获得最佳传输速率?

private static void SendFile(string filename, NetworkStream stream, int sendBufferSize)
{
    using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 4096, FileOptions.Asynchronous | FileOptions.SequentialScan))
    using (var ds = new DeflateStream(stream, CompressionMode.Compress))
    {
        StreamUtilities.CopyAsync(fs, ds, sendBufferSize);
    }
}

public static void CopyAsync(Stream sourceStream, Stream destStream, int bufferSize = 4096)
{
    Byte[] bufferA = new Byte[bufferSize];
    Byte[] bufferB = new Byte[bufferSize];

    IAsyncResult writeResult = null;
    IAsyncResult readResult = null;

    bool readBufferA = false;
    int read;

    readResult = sourceStream.BeginRead(bufferA, 0, bufferA.Length, null, null);
    //Complete last read
    while ((read = sourceStream.EndRead(readResult)) > 0)
    {
        if (readBufferA)
        {
            PerformOperations(sourceStream, destStream, bufferA, bufferB, ref readResult, ref writeResult, read);
        }
        else
        {
            PerformOperations(sourceStream, destStream, bufferB, bufferA, ref readResult, ref writeResult, read);
        }

        //Flip the bit on the next buffer
        readBufferA = !readBufferA;
    }
    if (writeResult != null)
        destStream.EndWrite(writeResult);
}

private static void PerformOperations(Stream sourceStream, Stream destStream, Byte[] readBuffer, Byte[] writeBuffer, ref IAsyncResult readResult, ref IAsyncResult writeResult, int bytesToWrite)
{
    //Start next read
    readResult = sourceStream.BeginRead(readBuffer, 0, readBuffer.Length, null, null);

    //End previous write
    if (writeResult != null)
        destStream.EndWrite(writeResult);
    writeResult = destStream.BeginWrite(writeBuffer, 0, bytesToWrite, null, null);
}

【问题讨论】:

  • 当然,压缩过程会拖慢你的速度……试着把它放在另一个线程上。
  • @YoryeNathan 我正在使用异步 I/O,读取和写入已经在单独的线程上(好吧,它不是真正的线程,它是内核中的 Aysnc IO 系统,但它具有相同的影响)
  • 是的,但是压缩和写 IO 在同一个线程上吗?每个压缩都应该有它自己的线程(嗯,有点),只要有“哇,我完成了!”通过压缩线程,发生异步写入操作。
  • 我相信它与读取 IO 在同一个线程上,我认为Jon's Answer 是我的解决方案,但我不想太快接受答案以阻止其他答案。
  • 在过去,您只是观察磁带驱动器,看看它们是否停止移动。啊我。

标签: c# networking .net-4.0 io compression


【解决方案1】:

一种选择是将这两个方面分离到生产者/消费者队列中:您的压缩器将块写入队列,然后由仅执行 ​​IO 的线程使用。

这样:

  • 您可以在 IO 发生时进行压缩,而无需进入异步 IO
  • 您可以检测您是否受 CPU 限制(队列通常为空,或短暂地有 1 个块)或受 IO 限制(随着您的压缩速度超过发送速度,队列逐渐变大)
  • 通过一些工作,您可以多线程压缩;您需要跟踪块顺序,但这应该是可行的。

【讨论】:

    猜你喜欢
    • 2017-06-22
    • 2011-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多