简体   繁体   English

Parallel.ForEach上的AccessViolationException

[英]AccessViolationException on Parallel.ForEach

Trying to run a Parallel.ForEach to lookup results from a external library, Z4DLL_NET. 尝试运行Parallel.ForEach从外部库Z4DLL_NET查找结果。 Documentation for the dll says the type is multi-thread safe. dll的文档说该类型是多线程安全的。 We have a large dataset which we are doing address verification on every month. 我们有一个庞大的数据集,每个月都要进行地址验证。

When running a any batch size larger than 1, I get the Access Violation Exception error on the _accumail.Lookup() in Lookup. 当运行任何大于1的批处理大小时,我在Lookup的_accumail.Lookup()上收到访问冲突异常错误。

I tried to reduce the amount of threads by using the MaxDegreeOfParallelism but it did not prevent this issue. 我试图通过使用MaxDegreeOfParallelism来减少线程数量,但是并不能阻止此问题。 Any thoughts would be greatly appreciated. 任何想法将不胜感激。

Web Service Code: Web服务代码:

    public void ProcessByBatchId(int batchId, int batchSize)
    {
        // get addresses to process
        var allAddresses = GetAddresses(batchId);

        var count = 0;

        // get initial set of addresses to process
        var addresses = ParseAddresses(allAddresses, count, batchSize).ToList();

        while (addresses.Any())
        {
            count += addresses.Count();

            // connect to db
            using (var entities = new Entities())
            {
                // turn these options off since they aren't needed here
                entities.Configuration.AutoDetectChangesEnabled = false;
                entities.Configuration.ValidateOnSaveEnabled = false;
                entities.Configuration.ProxyCreationEnabled = false;
                entities.Configuration.LazyLoadingEnabled = false;

                // process each address in parallel
                Parallel.ForEach(
                    addresses, 
                    addr =>
                {
                    // create dictionary for processing
                    var fields = GetFields(addr);

                    using (var addressValidator = _addressValidatorFactory.Create())
                    {
                        // lookup
                        var results = addressValidator.Lookup(fields);

                        SetResults(addr, results);
                    }
                });

                // set entity as changed for update
                addresses.ForEach(addr => entities.Entry(addr).State = EntityState.Modified);

                // commit changes to db
                entities.SaveChanges();

                // get next set of addresses to process
                addresses = ParseAddresses(allAddresses, count, batchSize).ToList();
            }
        }


    }

Lookup Code: 查询代码:

    public ValidationResults Lookup(IDictionary<FieldEnum, string> values)
    {
        IDictionary<FieldEnum, string> results = null;

        try
        {
            // load each value into accumail obj
            foreach (var field in Enum.GetNames(typeof(FieldEnum)))
            {
                var z4Field = (Z4DLL.Field)Enum.Parse(typeof(Z4DLL.Field), field);
                var fieldEnum = (FieldEnum)Enum.Parse(typeof(FieldEnum), field);

                if (values.ContainsKey(fieldEnum))
                {
                    _accumail.PutField(z4Field, values[fieldEnum] ?? string.Empty);
                    continue;
                }

                _accumail.PutField(z4Field, string.Empty);
            }

            // perform lookup
            if (_accumail.Lookup())
            {
                results = new Dictionary<FieldEnum, string>();

                // get each field from accumail obj
                foreach (var field in Enum.GetNames(typeof(FieldEnum)))
                {
                    results.Add((FieldEnum)Enum.Parse(typeof(FieldEnum), field),
                                _accumail.GetField((Z4DLL.Field)Enum.Parse(typeof(Z4DLL.Field), field)));
                }
            }

            var errorNum = _accumail.GetErrorNum();

            return new ValidationResults(results, errorNum, _accumail.GetErrorMsg(errorNum));
        }
        catch
        {
            var errorNum = _accumail.GetErrorNum();

            return new ValidationResults(results, errorNum, _accumail.GetErrorMsg(errorNum));
        }
    }

Error Description: 错误说明:

System.AccessViolationException was unhandled HResult=-2147467261 未处理System.AccessViolationException HResult = -2147467261
Message=Attempted to read or write protected memory. Message =尝试读取或写入受保护的内存。 This is often an indication that other memory is corrupt. 这通常表明其他内存已损坏。 Source=Z4DLL32_NET 来源= Z4DLL32_NET
StackTrace: at Smartsoft.Toolkit.Z4DLL.Lookup() at Accumail.AccumailAddressValidator.Lookup(IDictionary 2 values) in AccumailAddressValidator.cs:line 50 at AddressValidationService.ProcessByBatchId>b__3_0(address_validation_detail addr) in AddressValidationService.svc.cs:line 145 at System.Threading.Tasks.Parallel.<>c__DisplayClass31_0 2.b__0(Int32 i) at System.Threading.Tasks.Parallel.<>c__DisplayClass17_0 1.b__1() at System.Threading.Tasks.Task.InnerInvoke() at System.Threading.Tasks.Task.InnerInvokeWithArg(Task childTask) at System.Threading.Tasks.Task.<>c__DisplayClass176_0.b__0(Object ) at System.Threading.Tasks.Task.InnerInvoke() at System.Threading.Tasks.Task.Execute() at System.Threading.Tasks.Task.ExecutionContextCallback(Object obj) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callba StackTrace:在Smartsoft.Toolkit.Z4DLL.Lookup()在Accumail.AccumailAddressValidator.Lookup(IDictionary 2个值)在AccumailAddressValidator.cs:第50行在AddressValidationService.ProcessByBatchId> b__3_0(AddressValidationService.svc.line在AddressValidationService.ProcessByBatchId >> System.Threading.Tasks.Parallel。<> c__DisplayClass31_0 2.b__0(Int32 i)在系统上System.Threading.Tasks.Task.InnerInvoke()在System.Threading.Tasks.Parallel。<> c__DisplayClass17_0 1.b__1()在System.Threading.Tasks.Parallel。位于System.Threading.Tasks.Task。<> c__DisplayClass176_0.b__0(Object)位于System.Threading.Tasks.Task.InnerInvoke()处于System.Threading.Tasks.Task.Execute处的Threading.Tasks.Task.InnerInvokeWithArg(Task childTask) ()在System.Threading.ExecutionContext.RunInternal(ExecutionContext执行上下文,ContextCallback回调,对象状态,布尔值saveSyncCtx)在System.Threading.ExecutionContext.Run(ExecutionContext执行上下文,ContextCallback卡利亚 ck, Object state, Boolean preserveSyncCtx) at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot) at System.Threading.Tasks.Task.ExecuteEntry(Boolean bPreventDoubleExecution) at System.Threading.Tasks.Task.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() at System.Threading.ThreadPoolWorkQueue.Dispatch() at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback() ck,对象状态,布尔型saveSyncCtx)(位于System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task&currentTaskSlot)位于System.Threading.Tasks.Task.ExecuteEntry(Boolean bPreventDoubleExecution)位于System.Threading.Tasks.Task.System.Threading.IThreadPoolWorkItem System.Threading.ThreadPoolWorkQueue.Dispatch()的System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()的.ExecuteWorkItem()

Edit: 编辑:

The type is 类型是

private readonly Z4DLL _accumail;

That is part of the Smartsoft.Toolkit. 这是Smartsoft.Toolkit的一部分。 When the AddressValidator gets initialized, the constructor has 当AddressValidator初始化时,构造函数具有

_accumail = new Z4DLL(databasePath);

You might have better luck using only one instance of your dll and calling it multiple times. 您可能只使用dll的一个实例并多次调用它会更好。

 using (var addressValidator = _addressValidatorFactory.Create())
 {               {

Parallel.ForEach(
                addresses, 
                addr =>
            {
                // create dictionary for processing
                var fields = GetFields(addr);

                                        // lookup
                    var results = addressValidator.Lookup(fields);

                    SetResults(addr, results);
                }
            });
 }

NOTE The above is intended as an example - I didn't test your logic to see if this will work without making other changes. 注意 :以上内容仅作为示例-我没有测试您的逻辑以查看是否可以在不进行其他更改的情况下工作。 The point is to show how it can be pulledoutside the for loop. 关键是要显示如何将其拉出for循环。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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