C# 如何使用多线程加速代码

C# 如何使用多线程加速代码,c#,C#,我已经编写了重复计算的代码,直到它使用此代码找到一个数据类型可以容纳的最大数字 int a = 0; int b = 1; int c = 0; for (int j = 0; j < 10000; j++) { c = a + b; txtOutput.Text = c.ToString();

我已经编写了重复计算的代码,直到它使用此代码找到一个数据类型可以容纳的最大数字

            int a = 0;
            int b = 1;
            int c = 0;

            for (int j = 0; j < 10000; j++)
            {
                c = a + b;
                txtOutput.Text = c.ToString();
                a = b;
                b = c;
            }
            Parallel.For(0, 1000000, i =>
            {
                for (int j = 0; j < 10000; j++)
                {
                    c = a + b;
                    txtOutput.Text = c.ToString();
                    a = b;
                    b = c;
                }
            });
inta=0;
int b=1;
int c=0;
对于(int j=0;j<10000;j++)
{
c=a+b;
txtOutput.Text=c.ToString();
a=b;
b=c;
}
如何使用task类或parallelism来加快计算速度,因为目前完成此计算几乎需要20分钟,我需要它在1分钟或更短的时间内完成,我尝试了此代码

            int a = 0;
            int b = 1;
            int c = 0;

            for (int j = 0; j < 10000; j++)
            {
                c = a + b;
                txtOutput.Text = c.ToString();
                a = b;
                b = c;
            }
            Parallel.For(0, 1000000, i =>
            {
                for (int j = 0; j < 10000; j++)
                {
                    c = a + b;
                    txtOutput.Text = c.ToString();
                    a = b;
                    b = c;
                }
            });
Parallel.For(0,1000000,i=>
{
对于(int j=0;j<10000;j++)
{
c=a+b;
txtOutput.Text=c.ToString();
a=b;
b=c;
}
});

但是它仍然需要同样的时间,我这样做是为了了解即将到来的项目的多线程循环,正如一般人所说的,如果你触摸UI,你将把你的应用程序移动到一个单线程的应用程序中

但有一件事我不明白:为什么每次计算都要更改文本框的内容?我很确定数据的变化会如此之快,以至于用户无法理解发生了什么

我建议您以以下方式更改代码:

  • 将计算放在自己的线程中,而不是UI线程中(因此,如果您在WinForm应用程序中工作,则不要放在“button.click”事件中)
  • 在大约100次计算后引发一个事件,将新数字作为EventArgs发送
  • 侦听事件并在触发事件时更改UI字段

让我们知道它是否对您有帮助。

简而言之,您不能。每次计算都使用上一次计算的结果,这意味着在上一次计算完成之前,任何计算都不能开始——您的算法在设计上是同步的。在尝试异步/多线程运行之前,需要将算法分解为独立的段,然后在最后合并。(注意,有更简单的方法来提高性能,而不是像其他人评论的那样,每次迭代都敲打文本框是一个好的开始)。下面是一个如何异步运行算法的简短示例

一旦将算法分解为独立的段,就可以使用Task.run在异步模式下运行它

 public async Task<ResultType> RunAlgorithm(){
     foreach(var segment in GetSegments()){
          //start processing each segment
          resultTaskList.Add(Task.Run(ProcessSegment(segment)));
     }
     foreach(var resultTask in resultTaskList)
         resultList.Add(await resultTask); //wait for each task to finish processing
     var result = CombineResults(resultList);//combine results to one final result
     return result;
 }
 public ResultType ProcessSegment(SegmentType segment){
     //sync code here
 }
 public List<SegmentType> GetSegments(){
     //break your sample/input data into smaller segments to be processed in parallel
 }
 public ResultType CombineResults(List<ResultType>){
    //take the results of each set of calculations and come up with the overall/total/combined answer
 }
public异步任务RunAlgorithm(){
foreach(GetSegments()中的var段){
//开始处理每个段
resultTaskList.Add(Task.Run(ProcessSegment(segment));
}
foreach(resultTask列表中的var resultTask)
Add(等待resultTask);//等待每个任务完成处理
var result=CombineResults(resultList);//将结果合并为一个最终结果
返回结果;
}
公共结果类型ProcessSegment(SegmentType段){
//在这里同步代码
}
公共列表GetSegments(){
//将样本/输入数据分成更小的段,以便并行处理
}
公共结果类型组合结果(列表){
//根据每组计算的结果得出总体/总体/组合答案
}
上面的代码是一个相当简单的并行任务示例。您可以为“GetSegments”方法、“ProcessSegment”方法和“CombineResults”方法定义合理的定义

注意,如果你开始太多的任务,你会使自己感到疲劳。您可以调整getSegments以返回X段,其中X是线程数。或者,您可以使用一些奇特的Task.wheny调用将其设置为一次仅运行X个任务。稍后我将给出后者的一个例子


您可能还希望根据最适合您的代码的方式使方法签名非常不同,这只是一个简单的示例。

只需将文本框移动到循环之外即可

    public long SerialCalc(int n)
    {            
        long a = 0, b = 1, c = 0;
        for (int j = 0; j < n; j++)
        {
            c = a + b;
            a = b;
            b = c;
        }
        return c;
    }
这将使它更快。事实上,当代码经过
long.MaxValue
时,它会多次溢出
long.MaxValue>,变成负值,一次又一次地经过零和
long.MaxValue

如果值为
1000000
,则不到1秒即可完成


UI是单线程的,没有必要编写多线程的任何东西来在这样一个紧密的循环中封送每个对UI的调用。这里有更大的问题要解决吗?如果您想知道一个数据类型可以容纳的最大值,可以使用
int.MaxValue
long.MaxValue
等。我这样做是为了了解即将到来的项目中的多线程,该项目需要一个类似的循环来计算大数。是的,您的问题只是在每个循环中更新一个文本框。所以所有这些更新都在一个线程中排队。删除该选项,然后再次运行实验。您不会使用
txtuput.Text=c.ToString()写入UI如果你想加速它。先进行计算,然后在屏幕上显示。不要更新内部循环中的UI。这是正确的答案,因为瓶颈是UI更新。在for循环中使用StringBuilder将使代码更快。使用线程将使代码变慢而不是变快。StringBuilder不会加快代码速度。这是一个赋值,而不是concat。我的意思是
txtOutput.Text=sb.ToString()
应该在循环之外完成。不建议在循环内使用普通字符串连接,因为它会生成大量需要垃圾收集的对象。