具有2种这样的核心类:
public void ReadAllData(List<Entity> entities){
//processing
foreach(Entity e in entities){
ReadSingleData(entities[i]);
}
//processing
}
public void ReadSingleData(Entity entity){
//processing
db.ReadFromDataBase();
//processing
}
我需要提高从数据库读取,填充集合等的性能。 我首先将此实现与Task Parallel库一起使用:
Action[] actions = new Action[entities.Count);
public void ReadAllData(List<Entity> entities){
//processing
for(int i = 0; i< entities.Count;i++){
actions[i] = new Action(() => ReadSingleData(entities[i]));
}
//processing
}
ParallelOptions op = new ParallelOptions();
op.MaxDegreeOfParallelism = 6; //number of logical cores
Parallel.Invoke(op, actions);
我使用了异步/等待方法:
Task<bool>[] tasks = new Task<bool>[entities.Count];
public void ReadAllData(List<Entity> entities){
//processing
for(int i = 0; i< entities.Count;i++){
tasks[i] = ReadSingleData(entities[i]);
}
Task.WaitAll(tasks);
//processing
}
public async Task<bool> ReadSingleData(Entity entity){
//processing
await Task.Run(() =>
db.ReadFromDataBase();
});
//processing
return flag;
}
以上只是伪代码。通过任务执行,我的速度提高了约35-40%(约30秒)。我的问题是并行库如何在内部工作?库是否使用第二种实现之类的任务?第一次实施会出什么问题? 谢谢。
答案 0 :(得分:1)
由于第二种方法中的异步来自<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:output method="text"/>
<xsl:template match="x">
<xsl:for-each select="b/a">
<xsl:value-of select="w" />
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
,因此它们应该大致相同。我的猜测是Task.Run()
比6大很多。您通常不需要设置MaxDegreeOfParallelism。
但是您应该考虑使用entities.Count
并且没有Task.Run()来正确地进行异步操作。
答案 1 :(得分:0)
区别在于,在某些情况下,Parallel.Invoke
不会为计划执行的每个动作生成任务,并且其行为类似于Parallel.ForEach
。更详细地讲,如果任务数大于显式指定的并行度(如您的情况)或由内核数定义,则Parallel.Invoke
拆分要分批调用的操作,以适应要求的并行度。单个批处理中的操作将顺序执行。相比之下,Task.Run
在绝大多数情况下会在线程池中安排执行时间。
在CPU密集型计算的情况下,Parallel.Invoke
逻辑将获胜,因为它意味着有效利用可用资源而不会引起争用。受I / O限制的操作会改变这种情况,因为在Parallel.Invoke
情况下,并且同时Parallel.Invoke
操作无法完全利用I / O带宽时,您可能会发现很多I / O争用数量是有限的(I / O发生时可能正在执行的其他操作可能只是批量等待)。 Task.Run
在这种情况下具有优势,因为没有并行度上限,它可以覆盖其余的争用。这就是为什么在特定情况下它可能会提高性能的原因。但是,这有一个缺点:如果不受控制,Task.Run
的应用可能会导致以下情况:线程池中的任务超载,并且必须生成新线程来服务传入的任务(当计划的I / O任务数量超过I / O带宽),进而可能导致性能下降。这就是为什么处理I / O限制操作的推荐方法是使用async/await
,因为它依赖于确保最佳I / O利用率的内部机制(例如I / O完成端口)。