C# 并行算法比顺序算法慢

C# 并行算法比顺序算法慢,c#,parallel-processing,C#,Parallel Processing,我花了最后几天时间创建代码的并行版本(大学作业),但我走到了死胡同(至少对我来说):并行版本的速度几乎是顺序版本的两倍,我不知道为什么。代码如下: Variables.GetMatrix(); int ThreadNumber = Environment.ProcessorCount/2; int SS = Variables.PopSize / ThreadNumber; //GeneticAlgorithm GA = new GeneticAlgorithm(); Stopwatch sto

我花了最后几天时间创建代码的并行版本(大学作业),但我走到了死胡同(至少对我来说):并行版本的速度几乎是顺序版本的两倍,我不知道为什么。代码如下:

Variables.GetMatrix();
int ThreadNumber = Environment.ProcessorCount/2;
int SS = Variables.PopSize / ThreadNumber;
//GeneticAlgorithm GA = new GeneticAlgorithm();
Stopwatch stopwatch = new Stopwatch(), st = new Stopwatch(), st1 = new Stopwatch();
List<Thread> ThreadList = new List<Thread>();
//List<Task> TaskList = new List<Task>();
GeneticAlgorithm[] SubPop = new GeneticAlgorithm[ThreadNumber];
Thread t;
//Task t;
ThreadVariables Instance = new ThreadVariables();

stopwatch.Start();
st.Start();
PopSettings();
InitialPopulation();
st.Stop();

//Lots of attributions...
int SPos = 0, EPos = SS;

for (int i = 0; i < ThreadNumber; i++)
{
    int temp = i, StartPos = SPos, EndPos = EPos;
    t = new Thread(() =>
    {
        SubPop[temp] = new GeneticAlgorithm(Population, NumSeq, SeqSize, MaxOffset, PopFit, Child, Instance, StartPos, EndPos);
        SubPop[temp].RunGA();
        SubPop[temp].ShowPopulation();
    });
    t.Start();
    ThreadList.Add(t);
    SPos = EPos;
    EPos += SS;
}

foreach (Thread a in ThreadList)
    a.Join();

double BestFit = SubPop[0].BestSol;
string BestAlign = SubPop[0].TV.Debug;

for (int i = 1; i < ThreadNumber; i++)
{
    if (BestFit < SubPop[i].BestSol)
    {
        BestFit = SubPop[i].BestSol;
        BestAlign = SubPop[i].TV.Debug;
        Variables.ResSave = SubPop[i].TV.ResSave;
        Variables.NumSeq = SubPop[i].TV.NumSeq;
    }
}
Variables.GetMatrix();
int ThreadNumber=Environment.ProcessorCount/2;
int SS=Variables.PopSize/ThreadNumber;
//GeneticAlgorithm GA=新的GeneticAlgorithm();
秒表秒表=新秒表(),st=新秒表(),st1=新秒表();
List ThreadList=新列表();
//List TaskList=新列表();
GeneticAlgorithm[]subtop=新的GeneticAlgorithm[ThreadNumber];
螺纹t;
//任务t;
ThreadVariables实例=新的ThreadVariables();
秒表。开始();
st.Start();
PopSettings();
初始人口();
st.Stop();
//很多归因。。。
int SPos=0,EPos=SS;
对于(int i=0;i
{
subtop[temp]=新的遗传算法(总体、NumSeq、SeqSize、MaxOffset、PopFit、子、实例、StartPos、EndPos);
子op[temp].RunGA();
子op[temp].ShowPopulation();
});
t、 Start();
添加(t);
SPos=EPos;
EPos+=SS;
}
foreach(线程列表中的线程a)
a、 Join();
双最佳拟合=子顶部[0]。最佳拟合;
字符串BestAlign=subtop[0]。TV.Debug;
对于(int i=1;i
基本上,代码创建一个对象类型的数组,instantinate并在数组的每个位置运行算法,最后收集对象数组的最佳值。这种类型的算法适用于三维数据数组,在并行版本中,我分配每个线程处理数组的一个范围,避免数据并发。尽管如此,我还是觉得时间很慢。。。有什么想法吗

我使用的是一个,它有四个内核(两个+两个超线程),但是任何数量的线程超过一个都会使代码运行变慢

对于并行运行的代码,我可以解释如下:


我发布的代码中调用的第二个方法进行了大约10000次迭代,每次迭代调用一个函数。这个函数可以调用其他函数,也可以不调用其他函数(每个线程跨两个不同的对象)并进行大量计算,这取决于一系列特定于算法的因素。一个线程的所有这些方法都在一个数据数组的某个区域工作,而其他线程无法访问该区域。

您自己创建线程,因此存在一些极端的开销。像建议的评论一样并行化。还要确保单个工作单元所需的时间足够长。单线程/工作单元应至少处于活动状态20毫秒

非常基本的东西。我建议您认真阅读.NET中多线程的工作原理

我看到你没有创建太多的线程。但最佳线程数不能仅从处理器数确定。内置的并行类有先进的算法来减少总时间


分区和线程是一些非常复杂的事情,需要大量的知识才能正确处理,因此除非您真正知道自己在做什么,否则请依赖并行类来为您处理它。

创建线程的开销很大

使用线程池而不是创建新线程,如下所示:

Variables.GetMatrix();
int ThreadNumber = Environment.ProcessorCount / 2;
int SS = Variables.PopSize / ThreadNumber;
//GeneticAlgorithm GA = new GeneticAlgorithm();
Stopwatch stopwatch = new Stopwatch(), st = new Stopwatch(), st1 = new Stopwatch();
List<WaitHandle> WaitList = new List<WaitHandle>();
//List<Task> TaskList = new List<Task>();
GeneticAlgorithm[] SubPop = new GeneticAlgorithm[ThreadNumber];
//Task t;
ThreadVariables Instance = new ThreadVariables();

stopwatch.Start();
st.Start();
PopSettings();
InitialPopulation();
st.Stop();
//lots of attributions...
int SPos = 0, EPos = SS;

for (int i = 0; i < ThreadNumber; i++)
{
    int temp = i, StartPos = SPos, EndPos = EPos;
    ManualResetEvent wg = new ManualResetEvent(false);
    WaitList.Add(wg);
    ThreadPool.QueueUserWorkItem((unused) =>
    {
        SubPop[temp] = new GeneticAlgorithm(Population, NumSeq, SeqSize, MaxOffset, PopFit, Child, Instance, StartPos, EndPos);
        SubPop[temp].RunGA();
        SubPop[temp].ShowPopulation();
        wg.Set();
    });

    SPos = EPos;
    EPos += SS;
}

ManualResetEvent.WaitAll(WaitList.ToArray());

double BestFit = SubPop[0].BestSol;
string BestAlign = SubPop[0].TV.Debug;

for (int i = 1; i < ThreadNumber; i++)
{
    if (BestFit < SubPop[i].BestSol)
    {
        BestFit = SubPop[i].BestSol;
        BestAlign = SubPop[i].TV.Debug;
        Variables.ResSave = SubPop[i].TV.ResSave;
        Variables.NumSeq = SubPop[i].TV.NumSeq;
    }
}
Variables.GetMatrix();
int ThreadNumber=Environment.ProcessorCount/2;
int SS=Variables.PopSize/ThreadNumber;
//GeneticAlgorithm GA=新的GeneticAlgorithm();
秒表秒表=新秒表(),st=新秒表(),st1=新秒表();
List WaitList=新列表();
//List TaskList=新列表();
GeneticAlgorithm[]subtop=新的GeneticAlgorithm[ThreadNumber];
//任务t;
ThreadVariables实例=新的ThreadVariables();
秒表。开始();
st.Start();
PopSettings();
初始人口();
st.Stop();
//很多归因。。。
int SPos=0,EPos=SS;
对于(int i=0;i
{
subtop[temp]=新的遗传算法(总体、NumSeq、SeqSize、MaxOffset、PopFit、子、实例、StartPos、EndPos);
子op[temp].RunGA();
子op[temp].ShowPopulation();
wg.Set();
});
SPos=EPos;
EPos+=SS;
}
ManualResetEvent.WaitAll(WaitList.ToArray());
双最佳拟合=子顶部[0]。最佳拟合;
字符串BestAlign=subtop[0]。TV.Debug;
对于(int i=1;i
请注意,我使用的是WaitHandles,而不是使用Join来等待线程执行。

有很多地方需要简化:

int ThreadNumber = Environment.ProcessorCount/2;
int SS = Variables.PopSize / ThreadNumber;
int numberOfTotalIterations = // I don't know what goes here.

var doneAlgorithms = Enumerable.Range(0, numberOfTotalIterations)
                               .AsParallel() // Makes the whole thing running in parallel
                               .WithDegreeOfParallelism(ThreadNumber) // We don't need this line if you want the system to manage the number of parallel processings.
                               .Select(index=> _runAlgorithmAndReturn(index,SS))
                               .ToArray(); // This is obsolete if you only need the collection of doneAlgorithms to determine the best one.
                                           // If not, keep it to prevent multiple enumerations.

// So we sort algorithms by BestSol ascending and take the first one to determine the "best".
// OrderBy causes a full enumeration, hence the above mentioned obsoletion of the ToArray() statement.
GeneticAlgorithm best = doneAlgorithms.OrderBy(algo => algo.BestSol).First();

BestFit = best.Bestsol;
BestAlign = best.TV.Debug;
Variables.ResSave = best.TV.ResSave;
Variables.NumSeq = best.TV.NumSeq;
并声明一个方法,使其更具可读性

/// <summary>
/// Runs a single algorithm and returns it
/// </summary>
private GeneticAlgorithm _runAlgorithmAndReturn(int index, int SS)
{
    int startPos = index * SS;
    int endPos = startPos + SS;
    var algo = new GeneticAlgorithm(Population, NumSeq, SeqSize, MaxOffset, PopFit, Child, Instance, startPos, endPos);
    algo.RunGA();
    algo.ShowPopulation();
    return algo;
}
//
///运行单个算法并返回它
/// 
私有遗传算法_runAlgorithmAndReturn(int-index,int-SS)
{
int startPos=索引*SS;
int endPos=startPos+SS;
var algo=新的遗传算法(总体、NumSeq、SeqSize、MaxOffset、PopFit、子、实例、startPos、endPos);
算法RunGA();
算法ShowPopulation();
返回算法;
}

a如何比较?如果它是一个快速算法,线程开销很容易抵消并行化的任何好处。它还包含可能导致并行操作变慢的信息。在非常快速的代码视图中…a.Join()可能是您出现问题的原因您没有向我们显示您尝试并行运行的实际代码-y