加速C#循环

时间:2014-08-01 15:55:41

标签: c# performance for-loop dynamic-programming

我正试图找到一种加快后续for loops速度的快速方法。 (只是有趣的理论东西)

我有以下程序

using System;
using System.Collections;
using System.Diagnostics;

namespace SpeedTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Stopwatch timer = new Stopwatch();
            timer.Start();

            ArrayList widgets = new ArrayList(50000);

            for (int i = 0; i < widgets.Capacity; i++)
            {
                widgets.Add(new Widget(i));
            }

            string ProcessingMessages = "";

            for (int i = 0; i < widgets.Count; i++)
            {
                Widget widgetToProcess = (Widget)widgets[i];
                ProcessingMessages += widgetToProcess.ProcessWidget();
                ProcessingMessages += "\r\n";
            }

            Console.WriteLine(ProcessingMessages);

            timer.Stop();

            Console.WriteLine(timer.Elapsed);
            Console.ReadLine();
        }
    }

    class Widget
    {
        public Widget()
        {
            this.CreatedDateTime = DateTime.Now;
        }

        public Widget(int ID) : this()
        {
            this.ID = ID;
        }

        public DateTime CreatedDateTime { get; set; }
        public int ID { get; set; }

        public string ProcessWidget()
        {
            int Z = this.ID + this.ID;
            string Message = "Widget ID " + this.ID;
            Message += " was created on ";
            Message += CreatedDateTime.Year + "-" + CreatedDateTime.Month + "-" + CreatedDateTime.Day + ", at ";
            Message += CreatedDateTime.Hour + ":" + CreatedDateTime.Minute + ", with a value of ";
            Message += Z.ToString();
            return Message;
        }
    }
}

如何才能加快这些for loops的速度?我知道实现并行性很有用,例如

for (int i = 0; i < widgets.Count; i += 10)
            {
                Widget widgetToProcess1 = (Widget)widgets[i];
                Widget widgetToProcess2 = (Widget)widgets[i+1];
                Widget widgetToProcess3 = (Widget)widgets[i+2];
                Widget widgetToProcess4 = (Widget)widgets[i+3];
                Widget widgetToProcess5 = (Widget)widgets[i+4];
                Widget widgetToProcess6 = (Widget)widgets[i + 5];
                Widget widgetToProcess7 = (Widget)widgets[i + 6];
                Widget widgetToProcess8 = (Widget)widgets[i + 7];
                Widget widgetToProcess9 = (Widget)widgets[i + 8];
                Widget widgetToProcess10 = (Widget)widgets[i + 9];
                ProcessingMessages += widgetToProcess1.ProcessWidget() + "\r\n" +
                    widgetToProcess2.ProcessWidget() + "\r\n" +
                    widgetToProcess3.ProcessWidget() + "\r\n" +
                    widgetToProcess4.ProcessWidget() + "\r\n" +
                    widgetToProcess5.ProcessWidget() + "\r\n" +
                    widgetToProcess6.ProcessWidget() + "\r\n" +
                    widgetToProcess7.ProcessWidget() + "\r\n" +
                    widgetToProcess8.ProcessWidget() + "\r\n" +
                    widgetToProcess9.ProcessWidget() + "\r\n" +
                    widgetToProcess10.ProcessWidget() + "\r\n";
             }

然而,这都是手动编写的。我试图找到一种方法来动态地分解大型任务/数组大小并更快地运行这些块。

在此寻找一些简单的想法/概念。或者,如果有比使用for循环更好的替代方案进行此测试。

3 个答案:

答案 0 :(得分:4)

对于初学者来说,你是在紧密的循环中进行字符串连接 - 不好,看看StringBuilder。

其次,您要在时间安排中设置测试场景。

第三,不清楚for循环的处理和ProcessWidget()方法的成本之间的相对成本是多少。当然,在这种方法中会进行任何优化吗?

向下滚动查看ProcessWidget()方法,您还可以通过删除所有字符串连接并使用一个大string.Format()次调用或StringBuilder替换来获益。此外,ID和CreatedDateTime看起来像不可变字段,也许值得将它们定义为readonly并在构造函数中预先创建字符串描述(如果它可能多次调用ProcessWidget())。

答案 1 :(得分:2)

您也可以考虑使用:

widgets.Cast<Widget>().AsParallel().ForAll(widgetToProcess => {...});

这样可以提高流程的性能,从4分钟到30秒不等(取决于CPU配置)。

答案 2 :(得分:0)

您可以使用StringBuilder并将控制台输出移动到ProcessWidget调用中,然后将数组填充和处理放入Parallel.For中来提高整体速度 总运行时间约为7秒

以下是修改过的代码:

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

using System.Collections;
using System.Diagnostics;

namespace parallelFor
{
    class Program
    {
        static void Main(string[] args)
        {
            Stopwatch timer = new Stopwatch();
            timer.Start();
            int size = 50000;
            ArrayList widgets = new ArrayList(size);

            Parallel.For(0, size, i =>
            {
                Widget w = new Widget((int)i);
                widgets.Add(w);
                w.ProcessWidget();
            });


            timer.Stop();

            Console.WriteLine(timer.Elapsed);
            Console.ReadLine();
        }
    }

    class Widget
    {
        public Widget()
        {
            this.CreatedDateTime = DateTime.Now;
        }

        public Widget(int ID)
            : this()
        {
            this.ID = ID;
        }

        public DateTime CreatedDateTime { get; set; }
        public int ID { get; set; }

        public void ProcessWidget()
        {
        int Z = this.ID + this.ID;
        string Message = "Widget ID " + this.ID;
        Message += " was created on ";
        Message += CreatedDateTime.Year + "-" + CreatedDateTime.Month + "-" + CreatedDateTime.Day + ", at ";
        Message += CreatedDateTime.Hour + ":" + CreatedDateTime.Minute + ", with a value of ";
        Message += Z.ToString();
        Console.WriteLine(Message);
        }
    }
}