Kai*_*ann 9 c# performance multithreading
我有以下代码(控制台应用程序的'Program.cs'的完整内容).'countUp'直到'countUp4'的单线程执行需要13秒,多线程执行21秒.
我有一个Intel Core i5-2400 @ 3.10 GHz,8 GB Ram,Windows 7 64 Bit.那么为什么mutli线程执行比单线程执行慢?
多线程对于不阻塞简单c#应用程序的主程序有用吗?多线程什么时候给我一个执行速度的优势?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
static int counter = 0;
static int counter2 = 0;
static int counter3 = 0;
static int counter4 = 0;
static void Main(string[] args)
{
Console.WriteLine("Without multithreading:");
Console.WriteLine("Start:" + DateTime.Now.ToString());
countUp();
countUp2();
countUp3();
countUp4();
Console.WriteLine("");
Console.WriteLine("With multithreading:");
Console.WriteLine("Start:" + DateTime.Now.ToString());
Thread thread1 = new Thread(new ThreadStart(countUp));
thread1.Start();
Thread thread2 = new Thread(new ThreadStart(countUp2));
thread2.Start();
Thread thread3 = new Thread(new ThreadStart(countUp3));
thread3.Start();
Thread thread4 = new Thread(new ThreadStart(countUp4));
thread4.Start();
Console.Read();
}
static void countUp()
{
for (double i = 0; i < 1000000000; i++)
{
counter++;
}
Console.WriteLine(counter.ToString());
Console.WriteLine(DateTime.Now.ToString());
}
static void countUp2()
{
for (double i = 0; i < 1000000000; i++)
{
counter2++;
}
Console.WriteLine(counter2.ToString());
Console.WriteLine(DateTime.Now.ToString());
}
static void countUp3()
{
for (double i = 0; i < 1000000000; i++)
{
counter3++;
}
Console.WriteLine(counter3.ToString());
Console.WriteLine(DateTime.Now.ToString());
}
static void countUp4()
{
for (double i = 0; i < 1000000000; i++)
{
counter4++;
}
Console.WriteLine(counter4.ToString());
Console.WriteLine(DateTime.Now.ToString());
}
}
}
Run Code Online (Sandbox Code Playgroud)
And*_*tan 20
这是一个你可能看不到的原因:假共享,因为这4个整数都在内存中并排存在.
更新 - 前几年的MSDN mags现在仅作为.chm文件提供- 所以你必须从这里获取MSDN Mag的'2008年10月版,并且在下载之后,你必须记住右击并"解锁"文件打开它之前,Windows资源管理器中的文件属性对话框(其他操作系统可用!).您正在寻找由Stephen Toub,Igor Ostrovsky和Huseyin Yildiz撰写的名为".Net Matters"的专栏
这篇文章(全部阅读 - 很精彩)展示了内存中并排的值如何在更新时最终导致阻塞,因为它们都位于同一个缓存行中.这是非常低级别的阻止,您无法从.Net代码禁用.但是,您可以强制将数据间隔得更远,以便保证或至少增加每个值将位于不同缓存行上的可能性.
这篇文章使用数组 - 但它可能会影响你.
要跟进下面的建议,您可以通过稍微更改代码来证明/反驳这一点:
class Program
{
class CounterHolder {
private int[] fakeInts = new int[1024];
public int Value = 0;
}
static CounterHolder counter1 = new CounterHolder();
static CounterHolder counter2 = new CounterHolder();
static CounterHolder counter3 = new CounterHolder();
static CounterHolder counter4 = new CounterHolder();
Run Code Online (Sandbox Code Playgroud)
然后修改您的线程函数以操纵Value每个计数器持有者的公共字段.
我让那些阵列真的比它们需要的要大得多,希望它能证明它更好:)
Andreas Zaltan就是答案.拿代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Diagnostics;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
//static int counter = 0;
//static int counter2 = 0;
//static int counter3 = 0;
//static int counter4 = 0;
class CounterHolder
{
private int[] fakeInts = new int[1024];
public int Value = 0;
}
static CounterHolder counter1 = new CounterHolder();
static CounterHolder counter2 = new CounterHolder();
static CounterHolder counter3 = new CounterHolder();
static CounterHolder counter4 = new CounterHolder();
static void Main(string[] args)
{
Console.WriteLine("Without multithreading:");
Console.WriteLine("Start: " + DateTime.Now.ToString());
Stopwatch sw = new Stopwatch();
sw.Start();
countUp();
countUp2();
countUp3();
countUp4();
sw.Stop();
Console.WriteLine("Time taken = " + sw.Elapsed.ToString());
Console.WriteLine("\nWith multithreading:");
Console.WriteLine("Start: " + DateTime.Now.ToString());
sw.Reset();
sw.Start();
Task task1 = Task.Factory.StartNew(() => countUp());
Task task2 = Task.Factory.StartNew(() => countUp2());
Task task3 = Task.Factory.StartNew(() => countUp3());
Task task4 = Task.Factory.StartNew(() => countUp4());
var continuation = Task.Factory.ContinueWhenAll(new[] { task1, task2, task3, task4 }, tasks =>
{
Console.WriteLine("Total Time taken = " + sw.Elapsed.ToString());
});
Console.Read();
}
static void countUp()
{
Stopwatch sw = new Stopwatch();
sw.Start();
for (double i = 0; i < 1000000000; i++)
counter1.Value++;
sw.Stop();
Console.WriteLine("Task countup took: " + sw.Elapsed.ToString());
}
static void countUp2()
{
Stopwatch sw = new Stopwatch();
sw.Start();
for (double i = 0; i < 1000000000; i++)
counter2.Value++;
sw.Stop();
Console.WriteLine("Task countUP2 took: " + sw.Elapsed.ToString());
}
static void countUp3()
{
Stopwatch sw = new Stopwatch();
sw.Start();
for (double i = 0; i < 1000000000; i++)
counter3.Value++;
sw.Stop();
Console.WriteLine("Task countUP2 took: " + sw.Elapsed.ToString());
}
static void countUp4()
{
Stopwatch sw = new Stopwatch();
sw.Start();
for (double i = 0; i < 1000000000; i++)
counter4.Value++;
sw.Stop();
Console.WriteLine("Task countUP2 took: " + sw.Elapsed.ToString());
}
}
}
Run Code Online (Sandbox Code Playgroud)
使用整数运行它,你得到的多线程版本运行速度稍慢.
Serial: 13.88s
Multi-threaded: 14.01
Run Code Online (Sandbox Code Playgroud)
使用上面的建议运行它,您将获得以下内容

为了清楚起见,我发布了这个...