增强线程的性能

时间:2015-01-07 19:04:01

标签: c# multithreading performance

我有一个带有启动按钮的应用程序,可以调用长时间运行时功能。为了 添加一个停止按钮我为此功能添加了一个线程,以避免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语句 这是在函数内部。如下所示:

  • 添加CancelationToken是为了能够在按下“停止”按钮时停止处理。

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

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");
    }       
}

UPDATE2: 在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();
    }

UPDATE3:  嗨bebosh,

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

我的功能如下:

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
        }
    };
}

3 个答案:

答案 0 :(得分:2)

Bebosh的回答非常好。为了进一步提高性能,可以在设置“thread.IsBackground = true;”后立即设置“.Priority = ThreadPriority.AboveNormal”来设置“线程”的ThreadPriority。

答案 1 :(得分:1)

你可以尝试这段代码:

    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);
            }
        }
    }

答案 2 :(得分:-1)

使用中断线程

        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();
        }