【发布时间】:2013-03-17 22:25:46
【问题描述】:
我终于得到了 VS2012 并得到了一个简单的演示,并正在努力检查异步和等待的潜在性能提升,但令我沮丧的是它更慢!可能我做错了什么,但也许你可以帮助我。 (我还添加了一个简单的 Threaded 解决方案,并且运行速度符合预期)
我的代码根据系统上的内核数(-1)使用一个类来对数组求和为同样的事情而失败,但使用 async/await。
代码:(请注意,您需要添加对System.Management 的引用才能使核心检测器正常工作)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Management;
using System.Diagnostics;
namespace AsyncSum
{
class Program
{
static string Results = "";
static void Main(string[] args)
{
Task t = Run();
t.Wait();
Console.WriteLine(Results);
Console.ReadKey();
}
static async Task Run()
{
Random random = new Random();
int[] huge = new int[1000000];
for (int i = 0; i < huge.Length; i++)
{
huge[i] = random.Next(2);
}
ArraySum summer = new ArraySum(huge);
Stopwatch sw = new Stopwatch();
sw.Restart();
long tSum = summer.Sum();
for (int i = 0; i < 100; i++)
{
tSum = summer.Sum();
}
long tticks = sw.ElapsedTicks / 100;
long aSum = await summer.SumAsync();
sw.Restart();
for (int i = 0; i < 100; i++)
{
aSum = await summer.SumAsync();
}
long aticks = sw.ElapsedTicks / 100;
long dSum = summer.SumThreaded();
sw.Restart();
for (int i = 0; i < 100; i++)
{
dSum = summer.SumThreaded();
}
long dticks = sw.ElapsedTicks / 100;
long pSum = summer.SumParallel();
sw.Restart();
for (int i = 0; i < 100; i++)
{
pSum = summer.SumParallel();
}
long pticks = sw.ElapsedTicks / 100;
Program.Results += String.Format("Regular Sum: {0} in {1} ticks\n", tSum, tticks);
Program.Results += String.Format("Async Sum: {0} in {1} ticks\n", aSum, aticks);
Program.Results += String.Format("Threaded Sum: {0} in {1} ticks\n", dSum, dticks);
Program.Results += String.Format("Parallel Sum: {0} in {1} ticks\n", pSum, pticks);
}
}
class ArraySum
{
int[] Data;
int ChunkSize = 1000;
int cores = 1;
public ArraySum(int[] data)
{
Data = data;
cores = 0;
foreach (var item in new System.Management.ManagementObjectSearcher("Select * from Win32_Processor").Get())
{
cores += int.Parse(item["NumberOfCores"].ToString());
}
cores--;
if (cores < 1) cores = 1;
ChunkSize = Data.Length / cores + 1;
}
public long Sum()
{
long sum = 0;
for (int i = 0; i < Data.Length; i++)
{
sum += Data[i];
}
return sum;
}
public async Task<long> SumAsync()
{
Task<long>[] psums = new Task<long>[cores];
for (int i = 0; i < psums.Length; i++)
{
int start = i * ChunkSize;
int end = start + ChunkSize;
psums[i] = Task.Run<long>(() =>
{
long asum = 0;
for (int a = start; a < end && a < Data.Length; a++)
{
asum += Data[a];
}
return asum;
});
}
long sum = 0;
for (int i = 0; i < psums.Length; i++)
{
sum += await psums[i];
}
return sum;
}
public long SumThreaded()
{
long sum = 0;
Thread[] threads = new Thread[cores];
long[] buckets = new long[cores];
for (int i = 0; i < cores; i++)
{
int start = i * ChunkSize;
int end = start + ChunkSize;
int bucket = i;
threads[i] = new Thread(new ThreadStart(() =>
{
long asum = 0;
for (int a = start; a < end && a < Data.Length; a++)
{
asum += Data[a];
}
buckets[bucket] = asum;
}));
threads[i].Start();
}
for (int i = 0; i < cores; i++)
{
threads[i].Join();
sum += buckets[i];
}
return sum;
}
public long SumParallel()
{
long sum = 0;
long[] buckets = new long[cores];
ParallelLoopResult lr = Parallel.For(0, cores, new Action<int>((i) =>
{
int start = i * ChunkSize;
int end = start + ChunkSize;
int bucket = i;
long asum = 0;
for (int a = start; a < end && a < Data.Length; a++)
{
asum += Data[a];
}
buckets[bucket] = asum;
}));
for (int i = 0; i < cores; i++)
{
sum += buckets[i];
}
return sum;
}
}
}
有什么想法吗?我做错了异步/等待吗?我很乐意尝试任何建议。
【问题讨论】:
-
好吧,首先,您的线程示例实际上不起作用。您没有同步对聚合总和变量的访问,那里存在竞争条件。
-
我在这里可能是错的,但我不认为它实际上是在使用多核。如果我了解我所读到的有关 C# 异步内容的内容,那么它所做的只是围绕每个任务创建状态机,而不是实际上进行任何并行处理。它只是围绕完成包装事件处理程序,所以一个核心仍在完成所有工作,只是有一堆额外的开销。您需要使用并行库才能看到差异。但我可能错了 - 仍然试图围绕所有异步和并行的东西。
-
@JoeEnos:对 Task.Run 的调用将任务调度到线程池。
-
@ohmusama:你应该使用
Stopwatch,而不是DateTime。 -
仔细看看你的程序:它不是比较“async”和“Join”;它正在测量 调度到线程池 vs 只是创建一大堆线程。 “等待”与它无关。
标签: c# multithreading performance .net-4.5 async-await