`
窗户纸
  • 浏览: 19465 次
  • 性别: Icon_minigender_1
  • 来自: 北京
最近访客 更多访客>>
社区版块
存档分类
最新评论

有关对耗时很大循环进行并行化优化的探讨之二:多重循环任务的并发处理

 
阅读更多

【引】

在上一篇有关并行化的《有关对耗时很大循环进行并行化优化的探讨 之一:并发搜索的处理》博文中,我们看到,不使用并行语言,而使用基本的编程语言配合多线程可以进行并行化处理,本文进一步将并行化操作进行一个简单封装,并开始完成一个并行化的数据操作,以供大家参考。

【多重循环的操作】

有很多方法可以实现并行查询,必须并行化Linq就是很不错的途径,相比linq to entity,真正实现了性能的有效提升,但如果考虑在循环中进行复杂的业务处理,进行独立的并行化编程会更有效的帮助我们实现系统的优化。

下面我们以一个简单的操作为例,看看如何自己做一个并行化的程序:

在如下的例程中,我们自定义了一个继承于datatable的TLoopTable对象,并向该表格添加500×5条Tdata记录,很不幸的是,每条tdata记录需要10毫秒才能生成。使用该TLoopTable对象填充到datagridview的时间是39秒左右,

我们就以此应用开始进行我们的并行化优化。
class TLoopTable : DataTable
{
public const int CON = 500;


public TLoopTable()
{
this.Columns.Add("C1");
this.Columns.Add("D1");
this.Columns.Add("E1");
this.Columns.Add("F1");
this.Columns.Add("G1");
}

public void AddRows()
{
List<LoopD> plist = new List<LoopD>();
plist.Add(new LoopD("C", 1));
plist.Add(new LoopD("D", 2));
plist.Add(new LoopD("E", 3));
plist.Add(new LoopD("F", 4));
plist.Add(new LoopD("G", 5));

for (int i = 0; i < CON; i++)
{
TData [] tdl = new TData [5];

foreach (LoopD p in plist)
{
tdl[p.Col -1] = new TData(p.Col, i, p.Str) ;
}
this.Rows.Add(tdl);
}

}

class LoopD
{
public int Col;
public string Str;
public LoopD(string s, int c)
{
Col = c ;
Str = s ;
}
}

class TData
{
public int Row;
public int Col;
public string Data;

public TData(int col, int row,string fStr)
{
Thread.Sleep(10);

Row = row;
Col = col;
Data = fStr + row.ToString();


}
public override string ToString()
{
return Data;
}
}
}

首先,我们将上一篇文章所用的并行化方法进行一下封装如下:

 1. 通过定义一个委托,在指定我们在并行化操作内的具体输入输出,我这样定义委托,目的是达到的效果是:如果特定的操作需要循环强行退出(如发生异常),则通过taskRst=false实现,同时返回一个object类型值,以便外部程序了解中途退出的原因。
public delegate object MyParaLoopTaskHandler(object[] sender, int i, out bool taskRst);

class ParaLoop
{
private ManualResetEvent _ParaEvent;
private int _ExecedParaCount;
private object SynParaObj = new object();

private int ExecutedParaCount
{
get
{
lock (SynParaObj)
{
return _ExecedParaCount;
}
}
set
{
lock (SynParaObj)
{
_ExecedParaCount = value;
}
}
}

bool _IsParaFin;

private bool IsParaFin
{
get
{
lock (SynParaObj)
{
return _IsParaFin;
}
}
set
{
lock (SynParaObj)
{
_IsParaFin = value;
}
}
}

private int _TotalQty;
private object _ParaLoop_Return;

public object ParaCompute(MyParaLoopTaskHandler loopTask, object[] inArg, int loopQty)
{
_ParaEvent = new ManualResetEvent(false);

_IsParaFin = false;
_ExecedParaCount = 0;
_TotalQty = loopQty;

for (int i = 0; i < _TotalQty; i++)
{
MyParaThread u = new MyParaThread();
u.EndTaskCallBack +=new EndTaskHandler(u_EndTaskCallBack);
u.BeginInvoke(loopTask, inArg, i);
}

//使用waitone进行阻塞,仅仅是保证外部调用时使用效果上与顺序执行相同,但如果希望使用异步处理,这里可以完全不用阻塞,而通过_EndTaskCallBack返回一个事件即可
_ParaEvent.WaitOne();

return _ParaLoop_Return;
}


void u_EndTaskCallBack(bool taskRst, object retVal)
{

if (IsParaFin)
return;

if (!taskRst)
{
_ParaLoop_Return = retVal;
_ParaEvent.Set();
return;
}

lock (SynParaObj)
{
ExecutedParaCount++;
if (ExecutedParaCount >= _TotalQty)
{
IsParaFin = true;
_ParaEvent.Set();
}
}
}
}

internal delegate void EndTaskHandler(bool taskRst,object retVal);

class MyParaThread
{
internal event EndTaskHandler EndTaskCallBack;

public void BeginInvoke(MyParaLoopTaskHandler thdTask, object[] sender,int i)
{
Thread p = new Thread(new ParameterizedThreadStart(DoThreadTask), 262144);
ParaTaskContent t = new ParaTaskContent(thdTask, sender,i);
p.Start(t);
}


private void DoThreadTask(object args)
{
ParaTaskContent c = args as ParaTaskContent;
bool rs = true;
object retval= c.Invoke( out rs );
if (EndTaskCallBack != null)
{
EndTaskCallBack(rs, retval);
}
}


class ParaTaskContent
{
public MyParaLoopTaskHandler _Task;
object[] _Sender;
int _Loop_i;

public ParaTaskContent(MyParaLoopTaskHandler thdTask, object[] sender,int loop_i)
{
_Task = thdTask;
_Sender = sender;
_Loop_i = loop_i;
}

public object Invoke(out bool rst)
{
return _Task.Invoke(_Sender, _Loop_i, out rst);
}
}

}

经过封装以后,外部程序只需要如此调用即可实现并行化操作:

1.定义一个要处理的委托:

MyParaLoopTaskHandler k = new MyParaLoopTaskHandler(PerformParaCompute);

2. 创建一个并行化对象

ParaLoop t = new ParaLoop();

3. 指定需要输入的内容

object[] inargs = new object[2];
inargs[0] = plist;
inargs[1] = rlist;

4. 执行并行化即可

t.ParaCompute(k, inargs,TLoopTable .CON );

而并行化的处理结果可以通过委托方法中定义的操作实现。在本例中,我们每次并行化操作是生成一行(5项TData记录)记录,但我们需要一个途径使并行化生成的行数据与自定义表格容器的行向对应,否则结果可能是显示顺序不是0,1,2,3,...,而是0,3,2,4,1...

为了实现此目的,我们就先生成空白的列表数据,同时创建一个有行标记的数据字典,生成完数据后,再一次填充入table中。以下就是实现的例程:

public void AddRows()
{
List<LoopD> plist = new List<LoopD>();
plist.Add(new LoopD("C", 1));
plist.Add(new LoopD("D", 2));
plist.Add(new LoopD("E", 3));
plist.Add(new LoopD("F", 4));
plist.Add(new LoopD("G", 5));

//生成空白表

for (int i=0;i<CON ;i++)
{
this.Rows.Add(new object [5]);
}

ParaLoop t = new ParaLoop();
Dictionary<int, TData[]> rlist = new Dictionary<int, TData[]>(); // 用于保证并行化数据的顺序与表格位置一致的数据字典
object[] inargs = new object[2];
inargs[0] = plist; //传递给并行处理程序 生成没行数据对应位置信息所需要的子循环体
inargs[1] = rlist; // 传递给并行处理程序位置数据字典


MyParaLoopTaskHandler k = new MyParaLoopTaskHandler(PerformParaCompute);

t.ParaCompute(k, inargs,TLoopTable .CON );

//并行化完成后,将数据字典填充到表格中。

foreach (int row in rlist.Keys)
{
foreach (TData d in rlist[row])
{
this.Rows[row][d.Col-1] = d;
}
}

}

//并行处理数据的执行方法

private object PerformParaCompute(object[] sender, int i, out bool taskRst)
{

object[] k = sender as object[];

//提取到输入数据,并进行转换

List<LoopD> loopsrc = k[0] as List<LoopD>;
Dictionary<int, TData[]> rlist = k[1] as Dictionary<int, TData[]>;


TData[] r = new TData[5];
foreach (LoopD l in loopsrc)
{
r[l.Col - 1] = new TData(l.Col, i, l.Str);
}
lock (rlist)
{
rlist.Add(i, r);
}

taskRst = true;
return null;
}

经过并行化改造前后的执行效率如下表

执行效率比较
串行执行 并行化执行
执行时间 39.072秒 2.172秒
CPU占用率 <1% 68%

可以看到,通过并行化改造,系统效率提升了20倍。哇噢。

分享到:
评论

相关推荐

    通过多线程任务处理大批量耗时业务并返回结果

    标题中的"通过多线程任务处理大批量耗时业务并返回结果"指的是在Java或其他支持多线程的编程语言中,如何有效地分配工作到多个线程,以便同时处理大量任务,并在任务完成后收集和处理结果。 描述中提到的"当监测到...

    Splash界面/启动界面中处理耗时任务演示代码

    本篇将深入探讨如何在Splash界面中处理耗时任务,并通过提供的"SplashDemo"压缩包中的代码进行实例解析。 一、Splash界面设计原则 1. 简洁:避免过多动画或复杂设计,以免延长启动时间。 2. 易于理解:用户应能快速...

    并发和并行以及他们的区别

    并行计算可以显著提升计算速度,尤其是在处理大量数据时,通过任务分解和并行化,可以将原本耗时的任务分割成多个小任务并同时执行,从而减少总体处理时间。在Java中,可以使用Java的并发库,如Fork/Join框架和...

    TBB并发容器 学习笔记

    例如,上述代码展示了如何使用`parallel_for`和`blocked_range`来并行处理一个简单的任务,模拟了耗时操作并在双核CPU上实现了近乎两倍的加速。 总的来说,TBB通过提供一系列高级并行算法和线程安全的容器,简化了...

    具有量子行为粒子群优化算法的并行化研究.pdf

    通过与二进制遗传算法(EA)、十进制遗传算法(SEA)以及传统的粒子群优化算法(PSO)的并行版本进行比较,可以量化并行化量子粒子优化算法在解决不同问题上的优势。 【优化效果分析】在相同的处理器时间内,如果...

    并行化遗传算法研究

    - 可以将大群体划分为若干个小群体,并在不同的计算节点上对这些小群体进行独立处理。这种方式特别适用于大规模问题,可以通过增加并行节点的数量来进一步提高计算效率。 #### 四、遗传算法的结构化并行模型 1. *...

    Linux应用程序多核并行化方法研究与实现

    通过实验,作者展示了应用程序在进行并行化处理前后性能的对比,证明了多核并行化改造带来的显著性能提升,并对其他开发者进行类似优化提供了有益的参考。 综上所述,Linux应用程序多核并行化方法研究与实现不仅...

    汇编语言程序设计之循环程序

    除了单重循环,汇编语言还支持多重循环,即在一个循环体内嵌套另一个循环,以处理更复杂的逻辑。例如,如果需要对矩阵进行逐元素运算,可能会使用两层循环,外层循环遍历矩阵的行,内层循环遍历列。 总的来说,掌握...

    基于大数据的并行化深度卷积神经网络优化算法.zip

    总的来说,基于大数据的并行化深度卷积神经网络优化算法旨在利用分布式计算资源,通过数据、模型并行以及优化算法的协同工作,提高深度学习在大规模数据集上的训练效率和模型性能。这一领域的研究涵盖了硬件优化、...

    Java秒杀系统方案优化 高性能高并发实战

    本文将围绕“Java秒杀系统方案优化与高性能高并发实战”这一主题,深入探讨相关的技术和策略。 #### 一、秒杀系统的挑战与需求分析 1. **高并发处理能力**:秒杀活动通常会在短时间内吸引大量用户访问,这就要求...

    高斯消去法SSE并行化

    通常,这涉及到数据的预处理,如对矩阵进行重排,以便更有效地利用SSE的并行处理能力。同时,需要注意避免数据依赖和流水线冲突,确保并行计算的正确性和效率。 LU分解是高斯消去法的一种优化形式,它将高斯消去法...

    高并发,多子系统 配置化,任务入库定时处理设计思想

    配置化和任务入库定时处理的设计思想则是优化系统架构、提高效率的重要手段。以下将详细阐述这些概念及其应用。 首先,"高并发"是指系统在同一时间能够处理大量用户的请求,这在互联网服务中尤其重要。实现高并发的...

    卷积神经网络的并行化研究

    卷积层中的神经元可以独立地对输入图像的不同部分进行处理,池化层则可以对局部区域进行下采样,这些操作不依赖于其他神经元的状态,因此易于并行化。 传统的CNN实现以串行方式为主,这意味着计算资源没有得到充分...

    SIFT算法GPU并行化研究.pdf

    本文还对 SIFT 算法的并行化实现进行了讨论,包括使用 CUDA 实现 SIFT 算法的并行化、使用 OpenCL 实现 SIFT 算法的并行化、使用 MPI 实现 SIFT 算法的并行化等。这些方法可以提高 SIFT 算法的计算速度,提高图像...

    8天玩转并行开发(C#并发)

    - **并行执行**:两个任务几乎同时启动,总耗时接近两个任务执行时间之和中最短的那个。 #### 五、Parallel.For应用实例 `Parallel.For`提供了一种并行执行循环的方法。它可以自动将循环体分配给不同的线程进行...

    毕设项目:基于SpringBoot的高并发选课系统.zip

    该项目是一个基于SpringBoot框架构建的高并发...以上是基于SpringBoot的高并发选课系统中的主要技术栈和涉及的知识点,通过这个项目,开发者可以深化对Java Web开发的理解,学习如何构建能够处理大规模并发的高效系统。

    Weblogic提高并发处理性能的设置

    ### Weblogic提高并发处理性能的设置 在现代企业级应用环境中,提高Weblogic服务器的并发处理能力是一项重要的优化措施。本文将详细介绍通过调整Weblogic线程数、设置JDBC缓冲池以及修改`startWeblogic.cmd`文件来...

    matlab开发-快速循环法

    在MATLAB开发中,"快速循环法"是一种优化计算效率的技术,尤其适用于处理大量数据或进行复杂计算的任务。这种技术通常涉及到算法的优化,目的是减少循环的执行时间,提高程序运行速度,同时保持结果的准确性。 快速...

    R语言并行计算实战_R语言并行计算_

    例如,当需要对一个大向量执行相同的操作,如计算每个元素的平方,传统方法会逐个进行,耗时较长。而在并行计算环境中,可以将向量分割成多个部分,每部分在一个核心上独立计算,最后合并结果。这种方式大大提高了...

Global site tag (gtag.js) - Google Analytics