[英]Executing same function from several async methods simultenously causes errors
Here is a piece of code, where I try to execute different async methods, that need to be executed in specific order (the await
, and Task.WhenAll()
parts).这是一段代码,我在其中尝试执行不同的异步方法,这些方法需要按特定顺序执行(
await
和Task.WhenAll()
部分)。
//Some other tasks before
Task<bool> taskIfcQuantityArea = Task.Run<bool>(() =>
{
return this.addGroupStringToDictionary("IfcQuantityArea");
});
Task<bool> taskIfcQuantityLength = Task.Run<bool>(() =>
{
return this.addGroupStringToDictionary("IfcQuantityLength");
});
Task<bool> taskIfcSiUnit = Task.Run<bool>(() =>
{
return addGroupStringToDictionary("IfcSiUnit");
});
Task<bool> taskIfcPropertySingleValue = Task.Run<bool>(() =>
{
return addGroupStringToDictionary("IfcPropertySingleValue");
});
//uses IfcPerson, IfcOrganization
Task<bool> taskIfcPersonAndOrganization = Task.Run<bool>(() =>
{
return addGroupStringToDictionary("IfcPersonAndOrganization");
});
//uses IfcOrganization
Task<bool> taskIfcApplication = Task.Run(async () =>
{
await taskIfcSiUnit;
return addGroupStringToDictionary("IfcApplication");
});
//uses IfcSiUnit
Task<bool> taskIfcMeasureWithUnit = Task.Run(async () =>
{
await taskIfcSiUnit;
return addGroupStringToDictionary("IfcMeasureWithUnit");
});
//some other tasks after.
When I do that job synchronously, all works fine, but when I do it in async, I have some random errors.当我同步执行该工作时,一切正常,但是当我异步执行时,我会遇到一些随机错误。 At every test, the errors come randomly.
在每次测试中,错误都是随机出现的。 The only thing I see that could go wrong, is they all execute the same function
addGroupStringToDictionary
.我看到的唯一可能 go 错误的是它们都执行相同的 function
addGroupStringToDictionary
。
Here is the function:这是 function:
private bool addGroupStringToDictionary(string typeName)
{
//int processCount = await Task.Run<int>(() =>
//{
GroupedListStrings groupElt = this.listGrouppedStrings.FirstOrDefault(x => x.Type == typeName.ToUpper());
if (groupElt != null)
{
List<string> listStringInGroup = groupElt.ListStrings;
foreach (string line in listStringInGroup)
{
try
{
if(typeName== "IfcLocalPlacement($")
{
typeName = "IfcLocalPlacement";
}
var type = Type.GetType("Ifc."+typeName);
if (typeName == "IfcPropertySingleValue" || typeName == "IfcDirection" || typeName == "IfcSiUnit" || typeName == "IfcQuantityLength" || typeName == "IfcQuantityArea" || typeName == "IfcQuantityVolume" || typeName == "IfcQuantityWeight")
{
try
{
object instance = Activator.CreateInstance(type, line);
this.addToListDictionary((IfcElement)instance);
}
catch
{
}
}
else if (typeName == "IfcOpeningElement")
{
try
{
object instance = Activator.CreateInstance(type, line, this.listDictionaries, this.DictionaryBolts);
this.addToListDictionary((IfcElement)instance);
}
catch
{
}
}
else
{
try
{
object instance = Activator.CreateInstance(type, line, this.listDictionaries);
this.addToListDictionary((IfcElement)instance);
}
catch
{
}
}
}
catch
{
this.addError(line);
}
}
this.listGrouppedStrings.Remove(groupElt);
this.reportProgressImport();
}
//return 100;
//});
this.reportProgressImport();
return true;
}
The catch got 1-2 times over a bit more than 1 million lines.捕获量超过 100 万行,增加了 1-2 倍。 At each test the errors come randomly.
在每次测试中,错误都是随机出现的。 Is it possible that running the function simultaneously from several async methods, this is what causes the problem?
是否有可能从多个异步方法同时运行 function,这就是导致问题的原因?
Here is the addToListDictionary
function:这是
addToListDictionary
function:
private void addToListDictionary(IfcElement elt)
{
if(elt.ErrorFound)
{
this.listReadButError.Add(elt);
return;
}
string type = elt.GetType().ToString();
if (elt is IfcRepere)
{
type = "Ifc.IfcRepere";
}
else if (elt is IfcRepereType)
{
type = "Ifc.IfcRepereType";
}
else if (elt is IfcPhysicalSimpleQuantity)
{
type = "Ifc.IfcPhysicalSimpleQuantity";
}
else if (elt is IfcProfileDef)
{
type = "Ifc.IfcProfileDef";
}
else if (elt is IfcGeometricRepresentationContext)
{
type = "Ifc.IfcGeometricRepresentationContext";
}
GroupDictionary group = this.ListDictionaries.FirstOrDefault(x => x.Name == type);
if(group==null)
{
group = new GroupDictionary { Name = type };
this.ListDictionaries.Add(group);
}
group.ListElements[elt.ID] = elt;
if (elt is IfcMechanicalFastener)
{
IfcMechanicalFastener bolt = (IfcMechanicalFastener)elt;
this.DictionaryBolts[bolt.Tag] = bolt;
}
else if(elt is IfcProject)
{
this.listProjects.Add((IfcProject)elt);
}
else if(elt is IfcElementAssembly ifcAss)
{
this.DictionaryIfcElementAssemblies[ifcAss.Key] = ifcAss;
}
}
Also some additive information about my ListDictionaries
:还有一些关于我的
ListDictionaries
的附加信息:
private List<GroupDictionary> listDictionaries = new List<GroupDictionary>();
public List<GroupDictionary> ListDictionaries { get { return this.listDictionaries; } set { this.listDictionaries = value; } }
And the class GroupDictionary
和 class
GroupDictionary
public class GroupDictionary
{
string name { get; set; }
public string Name { get { return this.name; } set { this.name = value; } }
public ConcurrentDictionary<int, IfcElement> ListElements = new ConcurrentDictionary<int, IfcElement>();
public GroupDictionary()
{
}
}
I made different GroupDictionary
because as soon as I don't need one of them, I delete it to free space.我制作了不同
GroupDictionary
,因为一旦我不需要其中之一,我就会将其删除以释放空间。 I have one dictionary with IfcPoint
, I need it to gt IfcPolyLine
(lines), but when I finish to treat all objects using IfcPoint
, I clear remove the corresponding GroupDictionary
in order to free some memory.我有一本带有
IfcPoint
的字典,我需要它来 gt IfcPolyLine
(行),但是当我完成使用IfcPoint
处理所有对象时,我清除了相应的GroupDictionary
以释放一些 memory。
You have a obvious thread-safety issues here (ie you are trying to perform some operation which is not thread safe from multiple threads at a time).你在这里有一个明显的线程安全问题(即你试图执行一些不是线程安全的操作,一次来自多个线程)。 There are multiple ways you can try tackling it - using
lock
's, or some synchronization primitives .有多种方法可以尝试解决它 - 使用
lock
或一些同步原语。 But in this case it seems that major source of issues is working with standard collections from multiple threads, which is not thread-safe (cause thread-safety usually comes with performance price and is not always needed).但在这种情况下,问题的主要来源似乎是从多个线程使用标准 collections,这不是线程安全的(因为线程安全通常伴随着性能代价,并不总是需要)。 You can start from switching to appropriate collections from
System.Collections.Concurrent
namespace.您可以从
System.Collections.Concurrent
命名空间切换到适当的 collections 开始。
To go down deeper I recommend free e-book by Joseph Albahari Threading in C# .为了深入了解 go,我推荐 Joseph Albahari Threading 在 C# 中编写的免费电子书。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.