我有一个1000x1000的矩阵,并且使用Emgu CV。 我尝试在此矩阵中找到元素索引。
所以我首先在Matlab中尝试
test_matrix=rand(1000,1000);
tic
[row,col]=find(test_matrix==test_matrix(1,1));
toc;
它在9.7毫秒内完成。
然后我在C#中使用经典的for循环。
for (int i = 0; i < element_matrix.Height; i++)
for (int j = 0; j < element_matrix.Width; j++)
if (element_matrix[i, j] == finding_element)
{
Find_Row_List.Add(i);
Find_Col_List.Add(j);
}
它在460毫秒内完成。
然后我将矩阵划分为10个小矩阵,并计算不同线程中的每个部分。
t1= new Thread(() => {
for(int i = 0; i < 100; i++)
{
for(int j=0;j<element_matrix.Width;j++)
{
if(element_matrix[i,j]==finding_element)
{
Find_Row_List.Add(i);
Find_Col_List.Add(j);
}
}
}
});
...
t1.Start();
t2.Start();
...
t10.Start();
t1.Join();
t2.Join();
...
t10.Join();
它在310毫秒内完成。
我对 20个小型矩阵和线程重复此过程。
它在380毫秒内完成。
然后我使用Parallel.For
Parallel.For(0, element_matrix.Height, i =>
{
for(int j = 0; j < element_matrix.Width; j++)
{
if(element_matrix[i,j]==finding_element)
{
Find_Row_List.Add(i);
Find_Col_List.Add(j);
}
}
});
它在224毫秒内完成。
我使用两个线程和Parallel.For
t1 = new Thread(() => {
Parallel.For(0, 500, i =>
{
for (int j = 0; j < element_matrix.Width; j++)
{
if (element_matrix[i, j] == finding_element)
{
Find_Row_List.Add(i);
Find_Col_List.Add(j);
}
}
});
});
t2 = new Thread(() => {
Parallel.For(500, 1000, i =>
{
for (int j = 0; j < element_matrix.Width; j++)
{
if (element_matrix[i, j] == finding_element)
{
Find_Row_List.Add(i);
Find_Col_List.Add(j);
}
}
});
});
t1.Start();
t2.Start();
t1.Join();
t2.Join();
它在240毫秒内完成。
摘要
**Method Duration (ms)**
------------------------ ------------
Matlab 9.7
For Loop (Classic) 460
For Loop (10 threads) 310
For Loop (20 threads) 380
Parallel.For 224
Parallel.For(2 threads) 250
所有持续时间均为10次计算的平均值。
我尝试了与Matlab一样快的不同方法来进行计算。最快的解决方案是Parallel.For(224 ms)。但是它比Matlab慢25倍。我怎样才能改善这个持续时间?
答案 0 :(得分:2)
您的并行对象不是线程安全的,
最快的方法是使用非托管代码,指针和(可能)线程
但这应该比您拥有的速度快
var width = Input.GetLength(0);
var height = Input.GetLength(1);
var array = new Point[width * height];
var count = 0;
fixed (Point* r = array)
fixed (double* pInput = Input)
{
var len = array.Length;
for (var i = 0; i < len; i++)
if (*(pInput + i) == someValue)
{
var temp = r + count++;
(*(temp)).X = i;
(*(temp)).Y = i / width;
}
var result = new Point[count];
Array.Copy(array, 0, result, 0, count);
return result;
}
----------------------------------------------------------------------------
Mode : Release (64Bit)
Test Framework : .NET Framework 4.7.1 (CLR 4.0.30319.42000)
----------------------------------------------------------------------------
Operating System : Microsoft Windows 10 Pro
Version : 10.0.17134
----------------------------------------------------------------------------
CPU Name : Intel(R) Core(TM) i7-2600 CPU @ 3.40GHz
Description : Intel64 Family 6 Model 42 Stepping 7
Cores (Threads) : 4 (8) : Architecture : x64
Clock Speed : 3401 MHz : Bus Speed : 100 MHz
L2Cache : 1 MB : L3Cache : 8 MB
----------------------------------------------------------------------------
结果
--- Standard input ---------------------------------------------------------
| Value | Average | Fastest | Cycles | Garbage | Test | Gain |
--- Scale 100 ----------------------------------------------- Time 0.163 ---
| Unsafe2 | 23.472 µs | 21.013 µs | 81.444 K | 0.000 B | N/A | 80.92 % |
| Index | 123.034 µs | 114.073 µs | 420.831 K | 0.000 B | Base | 0.00 % |
--- Scale 1,000 -------------------------------------------- Time 16.477 ---
| Unsafe2 | 2.940 ms | 2.324 ms | 9.761 M | 0.000 B | N/A | 76.77 % |
| Index | 12.657 ms | 12.021 ms | 43.033 M | 0.000 B | Base | 0.00 % |
----------------------------------------------------------------------------
您可以并行进行,虽然我不确定TPL会带来这么多的性能提升,尽管您会获得一些收益,但是工作量会更多
答案 1 :(得分:0)
您是否已进入“ Math.Net”库以进行多维操作。
var sw = new Stopwatch();
sw.Start();
var test_matrix = Matrix<double>.Build.Dense(1000, 1000, 0);
double finding_Element = 1;
test_matrix[999, 999] = finding_Element;
test_matrix[998, 999] = finding_Element;
var result = new List<ValueTuple<int, int>>();
for (int row = 0; row < 1000; row++)
{
for (int column = 0; column < 1000; column++)
{
if (test_matrix[row, column] == finding_Element)
{
result.Add(new ValueTuple<int, int>(row, column));
}
}
}
sw.Stop();
Console.WriteLine("Find List of Result: " + sw.ElapsedMilliseconds + "ms");
var sw1 = new Stopwatch();
sw1.Start();
var result2 = test_matrix.Find(x => x.Equals(finding_Element)); // First Value
sw1.Stop();
Console.WriteLine("Find First Occurence: " + sw.ElapsedMilliseconds + "ms");
Console.ReadLine();
我在这里的结果大约是34毫秒以获取出现或首次出现的列表