增强线程性能

Enhance performance for threading

我有一个带有启动按钮的应用程序,它调用了一个长时间运行的函数。为了 添加一个停止按钮我为此功能添加了一个线程以避免 UI 冻结并能够随时停止处理。

没有线程的代码平均需要 12 分钟才能完成处理,但是有线程的代码如下所示 需要 4 倍以上。下面显示了开始按钮的代码,其中调用了函数 "LongRunningFunction" 。功能 需要一个字符串参数才能工作 "LongRunningFunction(Somestring)".

我已经用 Task.Run 和 Task.Factory.StartNew 进行了测试,但这两种方法都发生了同样的情况。

是否有另一种方法可以为我的情况设置一个不会对性能造成太大影响的线程?

public partial class Form1 : Form
{
    CancellationTokenSource cts = new CancellationTokenSource(); // Create the token source.
    public Form1()
    {
        InitializeComponent();
    }
    private void Start_Click(object sender, EventArgs e)
    {
        if (cts != null)
        {
            cts.Cancel();
        }
        cts = new CancellationTokenSource();
        Task.Run(()=> LongRunningFunction(Somestring, cts.Token), cts.Token);            
        //Task.Factory.StartNew(() => LongRunningFunction(Somestring, cts.Token), cts.Token, TaskCreationOptions.None, TaskScheduler.Default); 
    }
    private void Stop_Click(object sender, EventArgs e)
    {
        if (cts != null)
        {
            cts.Cancel();
            cts = null;
            MessageBox.Show("Processing cancelled");
        }
    }
    public void LongRunningFunction(string String, CancellationToken token)
    {
        //Long running processing
        //...
        MessageBox.Show("Processing finished");
    }
}

更新: 我唯一改变的是我声明函数的方式并在 while 循环中添加了一个 if 语句 那是在函数内部。如下所示:

没有线程,我这样声明函数:

public void LongRunningFunction(string String) 
{ 
    while (condition)
    {
        //My code within While loop
    }
    MessageBox.Show("Processing finished");
}

在 Thread 中,我定义了这样的函数:

public void LongRunningFunction(string String, CancellationToken token) 
{ 
    while (condition)
    {
        if (token.IsCancellationRequested)
        {
            break;
        }       
        //My code within While loop
    }
    if (!token.IsCancellationRequested)
    {
        MessageBox.Show("Processing finished");
    }       
}

更新2: LongRunningFunction() 内部调用了另一个打印行的函数。如下图。

    public void LongRunningFunction(string fileName, CancellationToken token)
    {
        StreamWriter writer = new StreamWriter(@outputfile, true, Encoding.UTF8, 4096);

        using (BinaryReader reader = new BinaryReader(File.Open(fileName, FileMode.Open)))
        {
            List<byte> buffer = new List<byte>();
            List<string> buffer1 = new List<string>();

            SoapHexBinary hex = new SoapHexBinary();

            while (chunk.Length > 0)
            {
                if (token.IsCancellationRequested) // ### For Cancel Thread ###
                {
                    break;
                }   // ### For Cancel Thread ###    

                    chunk = reader.ReadBytes(1024);

                    foreach (byte data in chunk)
                    {
                        if (somecondition)
                        {
                            buffer.Add(data);                           
                        }
                        else if (other condition)
                        {
                            buffer.Add(data);
                            PrintFunction(buffer, hex, outputfile, writer); // Print Line
                        }
                        else if (some other condition)
                        {
                            buffer.Add(data);
                        }
                    }                   
            }           
            if (!token.IsCancellationRequested)
            {
                MessageBox.Show("Processing finished");
            }

        }

        if (writer != null)
        {
            writer.Dispose();
            writer.Close();
        }
    }       
    private void PrintFunction(List<byte> buffer, SoapHexBinary hex, string outputfile, StreamWriter writer)
    {
            if (buffer.Count > 0)
            {
                if (buffer.Count >= lowlimit)
                {
                    hex.Value = buffer.ToArray();
                    string Register = hex.ToString();

                    Regex pattern1 = new Regex(@"some pattern");

                    if (pattern1.IsMatch(Register))
                    {
                        Match l1 = Regex.Match(Register, @"somepattern", RegexOptions.IgnoreCase | RegexOptions.Compiled);
                        writer.Write("{0}|{1}|{2}", Convert.ToInt32(l1.Groups[1].ToString(), 16), l1.Groups[2].Value, l1.Groups[3].Value);
                        Match l2 = Regex.Match(Register, @"otherpattern", RegexOptions.IgnoreCase | RegexOptions.Compiled);
                        if (l2.Success)
                        {
                            foreach (Match m in Regex.Matches(l2.Groups[2].ToString(), pattern2, RegexOptions.IgnoreCase | RegexOptions.Compiled))
                            {
                                //Some foreach code
                            }
                            foreach (Match x in Regex.Matches(var, @"pattern"))
                            {
                                //come code
                            }
                            writer.WriteLine("," + String.Join(",", var1));
                        }
                        else
                        {
                            writer.WriteLine();
                        }
                    }
                }
            }
            buffer.Clear();
    }

更新3: 嗨,贝博什,

我仍然怀疑如何在我的函数中应用,以及您在示例函数中定义委托的方式。

我的函数如下所示:

public void LongRunningFunction(string fileName)
{
    using (BinaryReader reader = new BinaryReader(File.Open(fileName, FileMode.Open)))
    {
        // some code
    }
}       

可能是这样的或者怎么样?:

private void LongRunningFunction(string fileName)
{
    MethodInvoker action = delegate
    {
        using (BinaryReader reader = new BinaryReader(File.Open(fileName, FileMode.Open)))
        {
            // some code
        }
    };
}

使用中断线程

        Thread thread;

        public MainWindow()
        {
            InitializeComponent();
        }

        private async void StartButtonClick(object sender, RoutedEventArgs e)
        {
            thread = new Thread(ExecuteLong);
            var task = Task.Run(() =>
                thread.Start());
            await task;
        }

        private void ExecuteLong()
        {
            try
            {
                // long task
            }
            catch (ThreadInterruptedException e)
            {
                MessageBox.Show("cancelled!");
                return;
            }
            MessageBox.Show("finished");
        }

        private void CancelButtonClick(object sender, RoutedEventArgs e)
        {
            this.thread.Interrupt();
        }

你能试试这个代码吗:

    bool Stop = false;
    Thread thread;

    private void StartButton_Click(object sender, EventArgs e)
    {
        string FileName = @"...\a.bin";
        thread = new Thread(new ThreadStart(() => DoLongProcess(FileName)));
        thread.IsBackground = true;
        thread.Start();
    }

    private void StopButton_Click(object sender, EventArgs e)
    {
        Stop = true;
    }


    private void DoLongProcess(string file)
    {
        using (BinaryReader reader = new BinaryReader(File.Open(file, FileMode.Open)))
        {
            int pos = 0;
            int length = (int)reader.BaseStream.Length;
            while (pos < length)
            {
                if (Stop)
                    thread.Abort();
                // using Invoke if you want cross UI objects
                this.Invoke((MethodInvoker)delegate
                {
                    label1.Text = pos.ToString();
                });
                pos += sizeof(int);
            }
        }
    }

Bebosh 的回答很好。要进一步提高性能,您可以通过在设置 "thread.IsBackground = true;".

后立即设置“.Priority = ThreadPriority.AboveNormal”来设置 "thread" 的 ThreadPriority