65.9K
CodeProject 正在变化。 阅读更多。
Home

后台周期计时

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.80/5 (6投票s)

2014年8月11日

CPOL

2分钟阅读

viewsIcon

22116

downloadIcon

173

用于计时后台任务的高精度计时器 EventArg 类。

引言

我经常需要监控后台进程中发生的事情,并且厌倦了以各种方式重写这段代码。所以我想分享我所拥有的,特别是考虑到我从大家那里得到了很多有用的代码片段。这是我提交的第一篇文章,在源代码格式化方面遇到了一些小麻烦;)。源代码本身格式正确。

背景

基本上,高精度计时函数来自微软:http://msdn.microsoft.com/en-us/library/aa964692(v=vs.85).aspx

那个例子是针对 Windows CE 的,所以我将 DllIMports 更改为“kernel32.dll”,而不是像他们示例中的“coredll.dll”,并添加了各种循环计时/显示方法。

然后我将其继承到一个非常基本的 EventArg 类中,就像 BackgroundWorker 类中使用的那样。因此,我的后台进程的计时细节将始终易于获取,因为这些参数会从 EventHandler 传递到 EventHandler,略有变化。

使用代码

除了 HiResTimer 类之外,我尽量使其保持简单。继承它的 EventArg 类非常基本,但您可以根据特定目的添加您想要的内容。HiResTimer 类的想法是一次编写,并轻松获得高分辨率计时细节,并且对实际执行的工作来说是某种程度的透明的。

除了将 HiResTimer 作为 EventArgs 类的一个基础之外,以下说明了以独立方式使用该类的方法

// add the ClassHighResTimer.cs file to your project
// add a StatusStrip with a label and a progress bar
// and a Button to your Form
// add these to your using statements
// using AbsoluteGenius;
// using System.Threading;
//
// then put this in as your button1_Click event code
private void button1_Click(object sender, EventArgs e)
{
    // this creates and inits cycle timing
    Utility.HiResTimer hiResTimer = new Utility.HiResTimer();
    Int64 totalCount = 1000; // loop counter total count
    // if there's a lot of processing before start
    // hiResTimer.StartTime = DateTime.Now; // (optional) will re-init cycle timing
    while (hiResTimer.CycleCount != totalCount - 1)
    { 
        //
        // do whatever work intended here
        Thread.Sleep(100);
        //
        hiResTimer.UpdateCycleStats(); // updates cycle stats and hiResTimer.CycleCount
        toolStripStatusLabel1.Text = " Run Time: " + hiResTimer.RunningTime 
                                   + " Avg Time: " + hiResTimer.CycleAvgTime
                                   + " Cycle Time: " + hiResTimer.CycleTime;
        toolStripProgressBar1.Value = hiResTimer.CyclePercentage(totalCount);
        statusStrip1.Refresh();
    }
    // do whatever post-loop processing (display/save data, etc.)
    // hiResTimer.EndTime = DateTime.Now; // (optional) logs completion of overall task
    toolStripStatusLabel1.Text = " Run Time: " + hiResTimer.RunningTime // the total while loop time
                               + " Avg Time: " + hiResTimer.CycleAvgTime// average while loop interval
                               + " Total Time: " + hiResTimer.TotalTime;// total task time 
                                                                        // (also logs completion and EndTime)
    // and that's all there is to it
}

EventArgs 类只是继承了相同的功能

public class HiResEventArgs : HiResTimer
{
    #region "Members"
    private object argument = null;
    public object RealResult = null;
    public object RealUserState = null;
    #endregion

    #region "Construction"
    public HiResEventArgs(object argument)
        : base() // base() inits the cycle timing
    {
        this.argument = argument; // pick up the argument
    }
    public static HiResEventArgs CopyOfHiResEventArgs(HiResEventArgs hiResEventArgs)
    {
        HiResEventArgs returnCopy = new HiResEventArgs(hiResEventArgs.argument);
        returnCopy.RealUserState = hiResEventArgs.RealUserState;
        returnCopy.RealResult = hiResEventArgs.RealResult;
        returnCopy.CopyHiResTimer(hiResEventArgs);
        return returnCopy;
    }
    #endregion

    #region "Properties"
    public object Argument
    {
        get { return argument; }
    }
    #endregion
}

因此,例如,将上述独立代码移动到 BackgroundWorker 类的 DoWork 函数中,将会非常相似,除了它将使用 HiResEventArgs 变量作为发送到它的参数/参数。

Utility.HiResEventArgs hiResArgs = new Utility.HiResEventArgs(100); // 100 loop total as argument
backgroundWorker1.RunWorkerAsync(hiResArgs); 

DoWork 函数将接收到它并像独立示例一样使用它,除了它不会显示任何内容

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    BackgroundWorker bw = sender as BackgroundWorker;
    Utility.HiResEventArgs hiResArgs = e.Argument as Utility.HiResEventArgs;
    // pick up the argument
    Int64 totalCount = 0; // loop counter total count
    Int64.TryParse((hiResArgs.Argument != null ? hiResArgs.Argument.ToString() : "100"), out totalCount);
    // if there's a lot of processing before start
    // hiResArgs.StartTime = DateTime.Now; // (optional) will re-init cycle timing
    while (hiResArgs.CycleCount < totalCount && !bw.CancellationPending)
    {
        //
        // do whatever work intended here
        Thread.Sleep(100);
        //
        hiResArgs.UpdateCycleStats(); // updates cycle stats and cycle counter
        hiResArgs.RealUserState = null; // (optional) fill this up with whatever state data you want 
        hiResArgs.RealResult = null; // (optional) fill this up with whatever result data you want 
        // send the hiResArgs to the ProgressChanged code as e.UserState
        bw.ReportProgress(hiResArgs.CyclePercentage(totalCount), // (important) sets total cycles 
        Utility.HiResEventArgs.CopyOfHiResEventArgs(hiResArgs)); // send a copy as e.UserState 
    }    
    // send the hiResArgs to the RunWorkerCompleted code as e.Result
    e.Result = Utility.HiResEventArgs.CopyOfHiResEventArgs(hiResArgs); // send a copy as e.Result
    // finally make sure to flag Cancel if necessary
    if (bw.CancellationPending)
        e.Cancel = true;
}

ProgressChanged 函数接管了先前

在独立示例中直接处理的进度显示

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    if (((BackgroundWorker)sender).CancellationPending)
        return;
    if (e.UserState != null && e.UserState.GetType().ToString().EndsWith("HiResEventArgs"))
    {
        Utility.HiResEventArgs hiResArgs = e.UserState as Utility.HiResEventArgs;
        toolStripStatusLabel1.Text = hiResArgs.CyclePercentage().ToString() + "% Done... "
                                   + " Run Time: " + hiResArgs.RunningTime
                                   + " Avg Time: " + hiResArgs.CycleAvgTime
                                   + " Cycle Time: " + hiResArgs.CycleTime;
        toolStripProgressBar1.Value = hiResArgs.CyclePercentage();
    }
    else
        toolStripProgressBar1.Value = e.ProgressPercentage;
    statusStrip1.Refresh();
}

最终结果和 TotalTime 将在 RunWorkerCompleted 事件处理程序中传递

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Cancelled == false && e.Error == null
    && e.Result != null && e.Result.GetType().ToString().EndsWith("HiResEventArgs"))
    {
        Utility.HiResEventArgs hiResArgs = e.Result as Utility.HiResEventArgs;
        // do whatever post-loop processing (display/save data, etc.)
        // hiResArgs.EndTime = DateTime.Now; // (optional) logs completion of overall task
        toolStripStatusLabel1.Text = hiResArgs.CyclePercentage().ToString() + "% Completed " 
                                   + " Run Time: " + hiResArgs.RunningTime  // the total while loop time
                                   + " Avg Time: " + hiResArgs.CycleAvgTime // average while loop interval
                                   + " Total Time: " + hiResArgs.TotalTime; // total task time 
                                                                            // (also logs completion and EndTime)
    }
    button1.Text = "Start";
}

 

肖恩·奥利里 (Sean O'Leary)

 

© . All rights reserved.