我有一个复杂的数学问题要解决,因此我决定并行进行一些独立的计算以缩短计算时间。在许多CAE程序中,例如ANSYS或SolidWorks,可以为此设置多个内核。
我创建了一个简单的Windows Form示例来说明我的问题。在此,功能CalculateStuff()
从功率的A
Sample
次的1.2
类中提高max
。对于2个任务,它是max / 2
次;对于4个任务,它是max / 4
次。
我只计算了一个CalculateStuff()
功能或四个重复的代码(CalculateStuff1(), ...2(), ...3(), ...4()
-每个任务一个)的运算时间,它们使用相同的代码。我不确定,对于每个任务使用相同的功能是否有意义(无论如何,Math.Pow
相同)。我也尝试启用或禁用ProgressBar。
该表表示所有12种情况的操作时间(秒)。我希望2和4个任务的速度会快2到4倍,但在某些情况下4个任务甚至比1还要差。我的计算机有2个处理器,每个10核。根据“调试”窗口,CPU使用率随着任务的增加而增加。我在这里的代码有什么问题,还是我误会了某些东西?为什么多项任务不能改善手术时间?
private readonly ulong max = 400000000ul;
// Sample class
private class Sample
{
public double A { get; set; } = 1.0;
}
// Clear WinForm elements
private void Clear()
{
PBar1.Value = PBar2.Value = PBar3.Value = PBar4.Value = 0;
TextBox.Text = "";
}
// Button that launches 1 task
private async void BThr1_Click(object sender, EventArgs e)
{
Clear();
DateTime start = DateTime.Now;
Sample sample = new Sample();
await Task.Delay(100);
Task t = Task.Run(() => CalculateStuff(sample, PBar1, max));
await t;
TextBox.Text = (DateTime.Now - start).ToString(@"hh\:mm\:ss");
t.Dispose();
}
// Button that launches 2 tasks
private async void BThr2_Click(object sender, EventArgs e)
{
Clear();
DateTime start = DateTime.Now;
Sample sample1 = new Sample();
Sample sample2 = new Sample();
await Task.Delay(100);
Task t1 = Task.Run(() => CalculateStuff(sample1, PBar1, max / 2));
Task t2 = Task.Run(() => CalculateStuff(sample2, PBar2, max / 2));
await t1; await t2;
TextBox.Text = (DateTime.Now - start).ToString(@"hh\:mm\:ss");
t1.Dispose(); t2.Dispose();
}
// Button that launches 4 tasks
private async void BThr4_Click(object sender, EventArgs e)
{
Clear();
DateTime start = DateTime.Now;
Sample sample1 = new Sample();
Sample sample2 = new Sample();
Sample sample3 = new Sample();
Sample sample4 = new Sample();
await Task.Delay(100);
Task t1 = Task.Run(() => CalculateStuff(sample1, PBar1, max / 4));
Task t2 = Task.Run(() => CalculateStuff(sample2, PBar2, max / 4));
Task t3 = Task.Run(() => CalculateStuff(sample3, PBar3, max / 4));
Task t4 = Task.Run(() => CalculateStuff(sample4, PBar4, max / 4));
await t1; await t2; await t3; await t4;
TextBox.Text = (DateTime.Now - start).ToString(@"hh\:mm\:ss");
t1.Dispose(); t2.Dispose(); t3.Dispose(); t4.Dispose();
}
// Calculate some math stuff
private static void CalculateStuff(Sample s, ProgressBar pb, ulong max)
{
ulong c = max / (ulong)pb.Maximum;
for (ulong i = 1; i <= max; i++)
{
s.A = Math.Pow(s.A, 1.2);
if (i % c == 0)
pb.Invoke(new Action(() => pb.Value = (int)(i / c)));
}
}
任务不是线程。 “异步”并不意味着“同时”。
有很多可能的原因,您可能看不到期望的性能提升,包括目前机器内核正在使用的其他东西。运行此精简版本的代码,并行运行时,我可以看到明显的改进:
不幸的是,我无法给您一个原因,除了可能与状态机魔术有关的事情之外,但这显着提高了性能: