如何限制.NET应用程序中的I/O操作?

Ana*_*oly 15 .net c# io limit

我正在开发一个应用程序(.NET 4.0,C#):
1.扫描文件系统.
2.打开并读取一些文件.

该应用程序将在后台运行,应该对磁盘使用率影响较小.如果用户正在执行常规任务并且磁盘使用率很高,则不应该打扰用户.反之亦然,如果没有人使用磁盘,应用程序可以更快.
主要问题是由于使用API​​(mapi32.dll)来读取文件,我不知道I/O操作的实际数量和大小.如果我要求API做某事我不知道它读取多少字节来处理我的响应.

那么问题是如何监控和管理磁盘使用情况?包括文件系统扫描和文件读取......

检查标准性能监视器工具使用的性能计数器?还是其他任何方式?

Nei*_*ick 19

使用System.Diagnostics.PerformanceCounter该类,附加到与要编制索引的驱动器相关的PhysicalDisk计数器.

下面是一些代码来说明,虽然它目前硬编码到"C:"驱动器.您需要将"C:"更改为您的进程扫描的任何驱动器.(这是粗略的示例代码,仅用于说明性能计数器的存在 - 不要将其视为提供准确信息 - 应始终仅用作指南.根据您自己的目的进行更改)

观察%空闲时间计数器,该计数器指示驱动器执行任何操作的频率. 0%空闲意味着磁盘正忙,但并不一定意味着它是平坦的并且无法传输更多数据.

%空闲时间当前磁盘队列长度相结合,这将告诉您驱动器是否变得如此繁忙以至于无法为所有数据请求提供服务.作为一般准则,任何超过0意味着驱动器可能是平坦的忙碌而超过2意味着驱动器完全饱和.这些规则适用于SSD和HDD.

此外,您读取的任何值都是某个时间点的瞬时值.你应该在几个结果上做一个运行平均值,例如每100ms读取一次读数并平均读取5次,然后再使用结果中的信息做出决定(即等到计数器结算然后再发出下一个IO请求).

internal DiskUsageMonitor(string driveName)
{

    // Get a list of the counters and look for "C:"

    var perfCategory = new PerformanceCounterCategory("PhysicalDisk");
    string[] instanceNames = perfCategory.GetInstanceNames();

    foreach (string name in instanceNames)
    {
        if (name.IndexOf("C:") > 0)
        {
            if (string.IsNullOrEmpty(driveName))
               driveName = name;
        }
    }


    _readBytesCounter = new PerformanceCounter("PhysicalDisk", 
                                               "Disk Read Bytes/sec", 
                                               driveName);

    _writeBytesCounter = new PerformanceCounter("PhysicalDisk", 
                                                "Disk Write Bytes/sec", 
                                                driveName);

    _diskQueueCounter = new PerformanceCounter("PhysicalDisk", 
                                               "Current Disk Queue Length", 
                                               driveName);

    _idleCounter = new PerformanceCounter("PhysicalDisk",
                                          "% Idle Time", 
                                          driveName);
    InitTimer();
}

internal event DiskUsageResultHander DiskUsageResult;

private void InitTimer()
{
    StopTimer();
    _perfTimer = new Timer(_updateResolutionMillisecs);
    _perfTimer.Elapsed += PerfTimerElapsed;
    _perfTimer.Start();
}

private void PerfTimerElapsed(object sender, ElapsedEventArgs e)
{
    float diskReads = _readBytesCounter.NextValue();
    float diskWrites = _writeBytesCounter.NextValue();
    float diskQueue = _diskQueueCounter.NextValue();
    float idlePercent = _idleCounter.NextValue();

    if (idlePercent > 100)
    {
        idlePercent = 100;
    }

    if (DiskUsageResult != null)
    {
        var stats = new DiskUsageStats
                        {
                                DriveName = _readBytesCounter.InstanceName,
                                DiskQueueLength = (int)diskQueue,
                                ReadBytesPerSec = (int)diskReads,
                                WriteBytesPerSec = (int)diskWrites,
                                DiskUsagePercent = 100 - (int)idlePercent
                        };
        DiskUsageResult(stats);
    }
}
Run Code Online (Sandbox Code Playgroud)