亨里克·克拉格
会员
- 已加入
- 2020年11月24日
- 留言内容
- 8
- 编程经验
- 10+
我在C#中拥有一个大型多线程系统,我意识到两个线程之间的性能差异很大。
现在,我设计了两个几乎完全相同的线程,其中一个线程的执行速度提高了4-5倍(并且如果您更改了它们必须运行的循环数量,它会线性扩展)。
和区别?
一种笨拙的条件围绕其中之一的实际重码。
对我来说这没有任何意义,而且如果这么小的细节可能产生如此巨大的影响,我将无能为力地进行优化。
这已在Unity中进行了测试,因此在其他环境中结果可能会有所不同。
ThreadA完成时间:2.8秒。
线程B finish time: 0.6 seconds.
提个醒"ThreadB"是具有条件的条件(在迭代时,该条件将在第一时间立即评估为true)。
如此愚蠢的代码添加如何使实际有效负载(for循环和数字运算)的执行速度如此之快?
另外,如果我更改"delay"带有静态变量"0.0"直接在ThreadB的条件下,它的性能再次类似于ThreadA。
换句话说:一个单精度双精度数,无论是硬编码值还是引用变量,都会使性能差异提高4-5倍。
不用管实际的算法,这只会使计算机处理一些数字。
我知道我要一次又一次地比较相同的数据,这很重要。
我不是编译专家,也没有办法研究实际的机器/汇编代码中的差异。
我只知道两者之间的差异是巨大的,对我来说是无意义的。
我想念什么?
我偶然发现了这一点,将来我可能无法知道给定线程以20%的可能速度执行,只要稍作更改就可以解决。
请。
我需要一个专家来使这一切从纯魔术变为现实"Oh, that's why...!
现在我知道将来如何避免它了...".
我知道C#的编译被托管的东西层包围,但是一定有逻辑上的原因。对?
这是一些测试代码,带有一些简单的结构来支持它。如果有人有时间检查他们是否获得与我相同的结果,我会很高兴。
现在,我设计了两个几乎完全相同的线程,其中一个线程的执行速度提高了4-5倍(并且如果您更改了它们必须运行的循环数量,它会线性扩展)。
和区别?
一种笨拙的条件围绕其中之一的实际重码。
对我来说这没有任何意义,而且如果这么小的细节可能产生如此巨大的影响,我将无能为力地进行优化。
这已在Unity中进行了测试,因此在其他环境中结果可能会有所不同。
ThreadA完成时间:2.8秒。
线程B finish time: 0.6 seconds.
提个醒"ThreadB"是具有条件的条件(在迭代时,该条件将在第一时间立即评估为true)。
如此愚蠢的代码添加如何使实际有效负载(for循环和数字运算)的执行速度如此之快?
另外,如果我更改"delay"带有静态变量"0.0"直接在ThreadB的条件下,它的性能再次类似于ThreadA。
换句话说:一个单精度双精度数,无论是硬编码值还是引用变量,都会使性能差异提高4-5倍。
不用管实际的算法,这只会使计算机处理一些数字。
我知道我要一次又一次地比较相同的数据,这很重要。
我不是编译专家,也没有办法研究实际的机器/汇编代码中的差异。
我只知道两者之间的差异是巨大的,对我来说是无意义的。
我想念什么?
我偶然发现了这一点,将来我可能无法知道给定线程以20%的可能速度执行,只要稍作更改就可以解决。
请。
我需要一个专家来使这一切从纯魔术变为现实"Oh, that's why...!
现在我知道将来如何避免它了...".
我知道C#的编译被托管的东西层包围,但是一定有逻辑上的原因。对?
这是一些测试代码,带有一些简单的结构来支持它。如果有人有时间检查他们是否获得与我相同的结果,我会很高兴。
C#:
using System.Threading;
public class ThreadTest
{
Thread threadA;
Thread threadB;
bool runThreadA = false;
bool runThreadB = false;
System.Diagnostics.Stopwatch stopWatch;
double elapsedTimeA = 0;
double elapsedTimeB = 0;
public ThreadTest()
{
stopWatch = new System.Diagnostics.Stopwatch();
StartThreads();
}
public void StartThreads ()
{
stopWatch.Reset();
stopWatch.Start();
threadA = new Thread(ThreadA);
threadB = new Thread(ThreadB);
runThreadA = true;
runThreadB = true;
elapsedTimeA = 0;
elapsedTimeB = 0;
threadA.Start();
threadB.Start();
}
void ThreadA ()
{
while (runThreadA)
{
runThreadA = false;
double preTicks = stopWatch.ElapsedTicks;
Line3Double lineA = new Line3Double(new Vector3DoublePrecision(10, 20, 30), new Vector3DoublePrecision(100, 140, 180));
Line3Double lineB = new Line3Double(new Vector3DoublePrecision(-10, -20, -30), new Vector3DoublePrecision(-100, -140, -180));
int lines = 1000;
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < lines; j++)
{
double aStartX = lineA.startX;
double aStartY = lineA.startY;
double aStartZ = lineA.startZ;
double aEndX = lineA.endX;
double aEndY = lineA.endY;
double aEndZ = lineA.endZ;
double aDirX = lineA.dirX;
double aDirY = lineA.dirY;
double aDirZ = lineA.dirZ;
double aDotSelf = lineA.dotSelf;
for (int k = 0; k < 8; k++)
{
for (int l = 0; l < lines; l++)
{
double wX = aStartX - lineB.startX;
double wY = aStartY - lineB.startY;
double wZ = aStartZ - lineB.startZ;
double b = aDirX * lineB.dirX + aDirY * lineB.dirY + aDirZ * lineB.dirZ;
double d = aDirX * wX + aDirY * wY + aDirZ * wZ;
double e = lineB.dirX * wX + lineB.dirY * wY + lineB.dirZ * wZ;
double D = aDotSelf * lineB.dotSelf - b * b;
double sc, tc;
if (D < 0.0000001)
{
// the lines are almost parallel
sc = 0.0f;
tc = (b > lineB.dotSelf ? d / b : e / lineB.dotSelf);
}
else
{
sc = (b * e - lineB.dotSelf * d) / D;
tc = (aDotSelf * e - b * d) / D;
}
double shortestX = wX + (sc * aDirX) - (tc * lineB.dirX);
double shortestY = wY + (sc * aDirY) - (tc * lineB.dirY);
double shortestZ = wZ + (sc * aDirZ) - (tc * lineB.dirZ);
double 距离 = shortestX * shortestX + shortestY * shortestY + shortestZ * shortestZ;
}
}
}
}
double postTicks = stopWatch.ElapsedTicks;
double time = ((postTicks - preTicks) / System.Diagnostics.Stopwatch.Frequency) * 1000;
elapsedTimeA = time;
}
}
void 线程B()
{
long startTicks = stopWatch.ElapsedTicks;
double 延迟 = 0;
while (runThreadB)
{
if ((double)(stopWatch.ElapsedTicks - startTicks) / System.Diagnostics.Stopwatch.Frequency >= 延迟)
{
runThreadB = false;
double preTicks = stopWatch.ElapsedTicks;
Line3Double lineA = new Line3Double(new Vector3DoublePrecision(10, 20, 30), new Vector3DoublePrecision(100, 140, 180));
Line3Double lineB = new Line3Double(new Vector3DoublePrecision(-10, -20, -30), new Vector3DoublePrecision(-100, -140, -180));
int lines = 1000;
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < lines; j++)
{
double aStartX = lineA.startX;
double aStartY = lineA.startY;
double aStartZ = lineA.startZ;
double aEndX = lineA.endX;
double aEndY = lineA.endY;
double aEndZ = lineA.endZ;
double aDirX = lineA.dirX;
double aDirY = lineA.dirY;
double aDirZ = lineA.dirZ;
double aDotSelf = lineA.dotSelf;
for (int k = 0; k < 8; k++)
{
for (int l = 0; l < lines; l++)
{
double wX = aStartX - lineB.startX;
double wY = aStartY - lineB.startY;
double wZ = aStartZ - lineB.startZ;
double b = aDirX * lineB.dirX + aDirY * lineB.dirY + aDirZ * lineB.dirZ;
double d = aDirX * wX + aDirY * wY + aDirZ * wZ;
double e = lineB.dirX * wX + lineB.dirY * wY + lineB.dirZ * wZ;
double D = aDotSelf * lineB.dotSelf - b * b;
double sc, tc;
if (D < 0.0000001)
{
// the lines are almost parallel
sc = 0.0f;
tc = (b > lineB.dotSelf ? d / b : e / lineB.dotSelf);
}
else
{
sc = (b * e - lineB.dotSelf * d) / D;
tc = (aDotSelf * e - b * d) / D;
}
double shortestX = wX + (sc * aDirX) - (tc * lineB.dirX);
double shortestY = wY + (sc * aDirY) - (tc * lineB.dirY);
double shortestZ = wZ + (sc * aDirZ) - (tc * lineB.dirZ);
double 距离 = shortestX * shortestX + shortestY * shortestY + shortestZ * shortestZ;
}
}
}
}
double postTicks = stopWatch.ElapsedTicks;
double time = ((postTicks - preTicks) / System.Diagnostics.Stopwatch.Frequency) * 1000;
elapsedTimeB = time;
}
}
}
}
public struct Vector3DoublePrecision
{
public double x;
public double y;
public double z;
public Vector3DoublePrecision(double x, double y, double z)
{
this.x = x;
this.y = y;
this.z = z;
}
}
public struct Line3Double
{
public double startX;
public double startY;
public double startZ;
public double endX;
public double endY;
public double endZ;
public double dirX;
public double dirY;
public double dirZ;
public double dotSelf;
public Line3Double(Vector3DoublePrecision start, Vector3DoublePrecision end)
{
startX = start.x;
startY = start.y;
startZ = start.z;
endX = end.x;
endY = end.y;
endZ = end.z;
dirX = end.x - start.x;
dirY = end.y - start.y;
dirZ = end.z - start.z;
dotSelf = dirX * dirX + dirY * dirY + dirZ * dirZ;
}
}