计算完成处理线程代码 C# 的挂起时间

Calculate pending time to finish processing threaded code C#

我有一个带线程的代码,我想显示完成处理的等待时间。按钮 1 调用 函数 "Function1()" 以 1024 字节的块读取文件,在 while 循环中控制,直到结束 的文件。在 "While loop" 中有一个 "foreach loop" 称为 "Function2()"。我开始 "while loop" 开始时的计时器并在 "while loop" 结束时停止。在那之后我正在尝试 计算大约等待时间,首先知道 "while loop" 将处理的迭代次数。 然后我保存 "elapsed time for the first iteration"(比方说 T1),然后我将它乘以迭代次数。

这将是

PendingTime = T1*Iterations.

那我做

PendingTime = PendingTime - Ti, where Ti is the ElapsedTime of the ith iteration.

问题是当我尝试使用真实代码时,T1*Iterations 的乘法给出了 402,实际上 处理需要12秒。

也许一些专家可以看出我做错了什么。提前致谢。

代码如下所示:

    async void button1_Click(object sender, EventArgs e)
    {
        //Some code
        await Task.Run(() => Function1(inputfile, cts.Token), cts.Token);
        //Some code
    }

    public void Function2()
    {
        //Some code
    }       

    public void Function1(string inputfile, CancellationToken token)
    {
        int buffer = 1024;
        int IterationCounter = 0;
        decimal Iterations = 1;  
        int PendingTime = 0;            

        using (BinaryReader reader = new BinaryReader(File.Open(inputfile, FileMode.Open)))
        {
            FileLength = (int)reader.BaseStream.Length;
            Iterations = (int)FileLength/buffer;                            

            while (chunk.Length > 0)
            {     
                Stopwatch sw1 = Stopwatch.StartNew(); //Start time counter              
                //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                //some code 
                chunk = reader.ReadBytes(buffer);

                foreach (byte data in chunk)
                {
                    //Some code
                    Function2(); //Call to Function2
                }
                //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 

                //Checking if it is the first iteration to save the pending time
                //Pending time would be the elapsed time for the first iteration
                //multiplied by the number of iterations (FileLength/1024).
                sw1.Stop(); //Stop time counter

                if (IterationCounter == 1)
                {
                    PendingTime =  (int)((decimal)Math.Round(sw1.Elapsed.TotalMilliseconds / 1000, 4)*Iterations);                      
                }                   
                //Show in TexBox1 the pending time
                TextBox1.Invoke((MethodInvoker)delegate
                {
                    PendingTime = PendingTime - (int)Math.Round(sw1.Elapsed.TotalMilliseconds / 1000, 4);                 
                    TextBox1.Text = PendingTime + " s";
                });
            }
        }
    }       

更新:

我正在根据 Peter Duniho 的示例使用以下代码进行测试。

可以用任何文件(即txt文件)进行测试。我已经用 5MB 的 txt 文件进行了测试,执行时间为 3 秒,但等待时间在 TextBox1 中始终显示为零。我哪里错了?

注意:我更改了这个:

double timePerIteration = sw1.Elapsed / ++IterationCounter;

至此

double timePerIteration = sw1.ElapsedMilliseconds/1000/ ++IterationCounter;

因为我收到错误:

Operator '/' cannot be applied to operands of type 'System.TimeSpan' and 'int' (CS0019)

到目前为止的代码是。感谢您的帮助。

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace TestTimer
{
    public partial class MainForm : Form
    {
        CancellationTokenSource cts = new CancellationTokenSource();
        string filename = "";
        long FileLength;
        FileInfo fInfo;
        Stopwatch sw1 =  new Stopwatch();

        public MainForm()
        {
            InitializeComponent();
        }

        void BtnSelectFileClick(object sender, EventArgs e)
        {

            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Title = "Select file";
            DialogResult dr = ofd.ShowDialog();

            if (dr == DialogResult.OK)
            {
                filename = ofd.FileName;
                fInfo = new FileInfo(filename);
            }
            else
            {
                MessageBox.Show("File not found");
                return;
            }           
        }   

        async void BtnRunProcessClick(object sender, System.EventArgs e)
        {

            cts = new CancellationTokenSource();            
            await Task.Run(() => Function1(filename, cts.Token), cts.Token);    
        }

    public void Function1(string inputfile, CancellationToken token)
    {
        int buffer = 1024;
        int IterationCounter = 0;
        int Iterations = 0;  
        double pendingTime = 0;            

        using (BinaryReader reader = new BinaryReader(File.Open(inputfile, FileMode.Open)))
        {
            FileLength = (int)reader.BaseStream.Length;
            Iterations = (int)FileLength/buffer;                           
            byte[] chunk;          

            sw1 = Stopwatch.StartNew(); //Start time counter

            while (true)
            {                               
                chunk = reader.ReadBytes(buffer);

                if (chunk.Length == 0) {break;}

                foreach  (byte data in chunk)
                {
                    Thread.Sleep(90/100);
                }

                // pendingTime is the current average time-per-iteration,
                // times the number of iterations left
                double timePerIteration = sw1.ElapsedMilliseconds/1000/ ++IterationCounter;
                pendingTime = timePerIteration * (Iterations - IterationCounter);

                TextBox1.Invoke((MethodInvoker)delegate
                {
                    // Let string.Format() take care of rounding for you
                    TextBox1.Text = string.Format("{0:0} s", pendingTime / 1000);
                });
            }
            MessageBox.Show("Execution time: " + string.Format("{0:0} s", sw1.ElapsedMilliseconds / 1000) );
        }
    }               

    }
}

我不明白您 post 编写的代码是如何实际编译的,更不用说工作了。 FileLength 变量似乎没有被声明,并且您永远不会增加 IterationCounter 变量,每次迭代都会给您一个负的 PendingTime 值。即使您增加了计数器,您的 PendingTime 变量的实际含义也会从计数器为 1 时执行的块和稍后当您从当前 PendingTime 中减去经过的时间时发生变化变量。

这表明您 post 编辑的代码并不是您正在使用的代码,因为显示的剩余时间总是负数(即使假设 FileLength 的声明刚刚得到由于某种原因不小心从你的 post 上掉了)。为了争论,我将添加一个执行递增的语句…

正如评论者 Chris 所说,当每次迭代的实际持续时间可能会有所不同时,就像这里的情况一样,您要做的最好的事情就是对当前迭代之前的所有迭代进行平均。即使这样也可能导致错误的剩余时间显示,每次迭代都会有相当大的变化(特别是如果迭代次数很少),但至少它更有可能接近。

像这样的东西可能更适合你:

public void Function1(string inputfile, CancellationToken token)
{
    int buffer = 1024;
    int IterationCounter = 0;
    int Iterations;

    using (BinaryReader reader = new BinaryReader(File.Open(inputfile, FileMode.Open)))
    {
        if (reader.BaseStream.Length == 0)
        {
            // nothing to do
            return;
        }

        // NOTE: this won't work for files with length > int.MaxValue!
        // Your original code has the same limitation, and I have not
        // bothered to change that.

        // Now that we know for sure the length is > 0, we can
        // do the following to ensure a correct iteration count
        Iterations = ((int)reader.BaseStream.Length - 1) / buffer + 1;

        Stopwatch sw1 = Stopwatch.StartNew();

        while (chunk.Length > 0)
        {     
            //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
            //some code 
            chunk = reader.ReadBytes(buffer);

            foreach (byte data in chunk)
            {
                //Some code
                Function2(); //Call to Function2
            }
            //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 

            // pendingTime is the current average time-per-iteration,
            // times the number of iterations left
            double timePerIteration = sw1.ElapsedMilliseconds / ++IterationCounter,
                pendingTime = timePerIteration *
                    (Iterations - IterationCounter);

            //Show in TexBox1 the pending time
            TextBox1.Invoke((MethodInvoker)delegate
            {
                // Let string.Format() take care of rounding for you
                TextBox1.Text = string.Format("{0:0} s", pendingTime / 1000);
            });
        }
    }
}

除非您保证输入文件的长度始终恰好是 1024 字节的倍数,否则您在计算总迭代次数时也有错误。我也在上面修复了这个问题。