简体   繁体   English

从多个异步方法同时执行相同的 function 会导致错误

[英]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).这是一段代码,我在其中尝试执行不同的异步方法,这些方法需要按特定顺序执行( awaitTask.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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM