Параллельная обработка в Linq и foreach

Это мой код:

        int j;
        WebShopEntities data = new WebShopEntities();
        var db = data;
        var list =
        (from line in System.IO.File.ReadLines(MyHttpApplication.GetAppDataPath() + "677254_dp_articles.TXT").AsParallel()
         where line.EndsWith(";") && !((line.StartsWith("prom_erp_partno")))
         let parts = line.Split('\t')
         select new WebShop.dp_articles
         {
             prom_erp_partno = parts[0],
             prom_mfm_partno = parts[1],
             prol_name = parts[2],
             mfm_short_name = parts[3],
             prom_prfm_id=int.TryParse(parts[4],out j)?int.Parse(parts[4]):0,
             prol_lng_id=int.Parse(parts[5]),
             prol_variant=parts[6]??null,
             vpl=parts[7]??null,
             status=parts[8],
             gross_weight=Decimal.Parse('0'+parts[9].Replace('.',',')),
             commodity_code=parts[10],
             returnable = parts[11].Replace(';', ' ').Trim()

         }).ToList();
        Parallel.ForEach(list, item =>
         {

             if (!(from x in db.dp_articles.AsParallel() where x.prom_erp_partno == item.prom_erp_partno select x).Any())
             {

                 db.dp_articles.Add(new dp_articles
                 {
                     prom_erp_partno = item.prom_erp_partno,
                     prom_mfm_partno = item.prom_mfm_partno,
                     prol_name = item.prol_name,
                     mfm_short_name = item.mfm_short_name,
                     prom_prfm_id = item.prom_prfm_id,
                     prol_lng_id = item.prol_lng_id,
                     prol_variant = item.prol_variant,
                     vpl = item.vpl,
                     status = item.status,
                     gross_weight = item.gross_weight,
                     commodity_code = item.commodity_code,
                     returnable = item.returnable

                 });
             }
             else
             {

                 var itemU = db.dp_articles.Find(item.prom_erp_partno);
                 itemU.prom_mfm_partno = item.prom_mfm_partno;
                 itemU.prol_name = item.prol_name;
                 itemU.mfm_short_name = item.mfm_short_name;
                 itemU.prom_prfm_id = item.prom_prfm_id;
                 itemU.prol_lng_id = item.prol_lng_id;
                 itemU.prol_variant = item.prol_variant;
                 itemU.vpl = item.vpl;
                 itemU.status = item.status;
                 itemU.gross_weight = item.gross_weight;
                 itemU.commodity_code = item.commodity_code;
                 itemU.returnable = item.returnable;
             }

             db.SaveChanges();
         });

Мне нужно выполнять эти процессы параллельно, но у меня нет информации о параллельных процессах в С#. После быстрого поиска в Google я нашел этот синтаксис параллелизма, но после того, как я его запустил, появилась эта ошибка:

Контекст нельзя использовать во время создания модели. Это исключение может быть вызвано, если контекст используется внутри метода OnModelCreating или если к одному и тому же экземпляру контекста одновременно обращаются несколько потоков. Обратите внимание, что члены экземпляра DbContext и связанных классов не гарантируют потокобезопасность.

и трассировка стека:

Этот код анализирует текстовый файл и пытается поместить его в базу данных или обновить, если он существует.

Короче говоря, вы используете EF одновременно из многих потоков. Это не разрешено. Сканируйте весь свой код и убедитесь, что у вас нет ни одного места, где вы используете один и тот же EF ObjectContext (и т. д.) из нескольких потоков.


person paradise_human    schedule 27.05.2014    source источник
comment
локальный хост asp.net mvc   -  person Nick Udell    schedule 27.05.2014
comment
Можете ли вы объяснить мне больше?   -  person paradise_human    schedule 27.05.2014


Ответы (2)


Вероятно, вам следует создать один контекст на поток или на единицу работы.

Эта ошибка обычно возникает, если вы пытаетесь использовать элемент списка до того, как весь набор результатов будет пронумерован (и обычно решается с помощью .AsEnumerable() или .ToList() в конце рассматриваемого запроса)

person usr    schedule 27.05.2014
comment
Конечно, спроси меня что-нибудь конкретное. Ожидается, что в Stack Overflow вы сами проведете базовое исследование и спросите, когда застряли. - person paradise_human; 27.05.2014
comment
Я использую это свойство для своего контекста данных: '[ThreadStatic] static WebShopEntities data = new WebShopEntities();' и я удалил "var db = data;" ошибка безопасного потока контекста данных исчезла, но появилась ссылка на объект, не установленная на экземпляр объекта. Как я могу это решить? Когда я использовал точку останова после входа в параллельный цикл foreach, моя ссылка на базу данных стала нулевой!!! - person usr; 27.05.2014
comment
Вы инициализировали переменную ThreadStatic во всех потоках или только в одном? - person paradise_human; 29.05.2014
comment
Я инициализировал его в части свойств класса: _1_ - person usr; 29.05.2014
comment
Вы не совсем понимаете, как работает ThreadStatic. Документы читает. - person paradise_human; 29.05.2014
comment
Я инициализировал его этим кодом: _1_, но после того, как он захотел сохранить его в базе данных, появилась эта ошибка: _2_ - person usr; 29.05.2014
comment
Как вы думаете, это сообщение об ошибке как-то связано с ThreadStatic? Как вы думаете, что это значит? - person paradise_human; 29.05.2014
comment
нет, это проблема с моим десятичным значением в базе данных. - person usr; 29.05.2014
comment
Когда я изменяю код на: if ((из x в db.dp_articles, где x.prom_erp_partno == item.prom_erp_partno select x).ToList().Count==0) Он говорит: Ссылка на объект не установлена ​​​​на экземпляр объект. - person paradise_human; 29.05.2014

В вашем случае я бы изменил строку:

и удалите .AsParallel() . Насколько я могу судить, он не служит никакой полезной цели и, вероятно, блокирует внутреннюю часть кода, потому что попытка добавления в db.dp_articles, пока другие потоки все еще запрашивают его, была бы небезопасной.

if (!(from x in db.dp_articles.AsParallel() where x.prom_erp_partno == item.prom_erp_partno select x).Any())

ИЗМЕНИТЬ

Также удалите .AsParallel() из этой строки:

для каждой строки файла вы создаете параллельный поток, который фильтрует ее в один и тот же список!

var list =
        (from line in System.IO.File.ReadLines(MyHttpApplication.GetAppDataPath() + "677254_dp_articles.TXT").AsParallel()

Где вы выполняете этот код?

person James S    schedule 27.05.2014
comment
Я удалил это, но он снова говорит: контекст нельзя использовать во время создания модели. Это исключение может быть вызвано, если контекст используется внутри метода OnModelCreating или если к одному и тому же экземпляру контекста одновременно обращаются несколько потоков. Обратите внимание, что члены экземпляра DbContext и связанных классов не гарантируют потокобезопасность. - person paradise_human; 27.05.2014
comment
переместите db.SaveChanges из бита Parallel. - person paradise_human; 27.05.2014
comment
Я поменял, ничего не изменилось. - person James S; 27.05.2014
comment
Хорошо, читая немного больше, кажется, что вы не можете использовать dataContext в нескольких потоках, потому что он не является потокобезопасным. Если вы настроены на параллельную вставку/обновление, вам придется либо создать контекст данных в каждом потоке, либо вернуться к прямым SQL-запросам. Честно говоря, я бы, наверное, вообще отказался от параллельной обработки, если только она не ужасно медленная. - person paradise_human; 27.05.2014
comment
[InvalidOperationException: контекст нельзя использовать во время создания модели. Это исключение может быть вызвано, если контекст используется внутри метода OnModelCreating или если к одному и тому же экземпляру контекста одновременно обращаются несколько потоков. Обратите внимание, что члены экземпляра DbContext и связанных классов не гарантируют потокобезопасность.] System.Data.Entity.Internal.LazyInternalContext.InitializeContext() +797 System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType) +18 System.Data.Entity.Internal.Linq.InternalSet_2_1.GetEnumerator() +15 System.Data.Entity.Infrastructure.DbQuery_3_1.InitializePartitions(IEnumerable_4_1..ctor(источник IEnumerable_5_1, Int32 partitionCount, Boolean useStriping) +277 System.Linq.Parallel .ScanEnumerableQueryOperatorResults.GivePartitionedStream (IPartitionedStreamRecipient_6_1 получатель) +578 System.Linq.Parallel.UnaryQueryOperatorResults.GivePartitionedStream (IPartitionedStreamRecipient_7_1.GetOpenedEnumerator (Nullable_8_1.OpenQuery () +218 System.Linq.Parallel.QueryOpeningEnumerator_9_1.Aggregate () +64 System.Linq.ParallelEnumerable. Any(предикат ParallelQuery_10_2) +92 System.Linq.ParallelEnumerable.Any(ParallelQuer y_11_2.b__23 (int32 i) +63 system.threading.tasks. <> C__displayClassf_12_1. +223 System.Threading.Tasks.Parallel.ForEachWorker(тело IEnumerable_19_1, Action_20_3 bodyWithStateAndIndex, Func_21_5 bodyWithEverything, Func_22_1 localFinally) +10893169 System.Threading.Tasks.Parallel.ForEach(тело IEnumerable_23_1) +110()Farshops.Art.Models в c:\Users\Ahmad\Documents\Visual Studio 2013\Projects\WebShop\WebShop\Models\Ftp.cs:366 webshop.Controllers.HomeController.Index() в c:\Users\Ahmad\Documents\Visual Studio 2013\ Projects\WebShop\WebShop\Controllers\HomeController.cs:46 lambda_method(Closure, ControllerBase, Object[]) +62 System.Web.Mvc.ActionMethodDispatcher.Execute(контроллер ControllerBase, параметры Object[]) +14 System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, параметры IDictionary_24_2) +27 System.Web.Mvc.Async.AsyncControllerActionInvoker.b__36(IAsyncResult asyncResult, ActionInvocation innerInvokeState) +22 System. Web.Mvc.Async.WrappedAsyncResult_25_1.End() +49 System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult) +32 System.Web.Mvc.Async.AsyncInvocationWithFilters.b__3c() +50 System.Web.Mvc .Async.‹>c__DisplayClass45.b__3e() +225 System.Web.Mvc.Async.‹>c__DisplayClass30.b__2f(IAsyncResult asyncResult) +10 System.Web.Mvc.Async.WrappedAsyncResult_26_1.End() +49 System.Web. Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethodWithFilters(IAsyncResult asyncResult) +34 System.Web.Mvc.Async.‹>c__DisplayClass28.b__19() +26 System.Web.Mvc.Async.‹>c__DisplayClass1e.b__1b(IAsyncResult asyncResult) +100 Система .Web.Mvc.Async.WrappedAsyncResult_27_1.End() +49 System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction(IAsyncResult asyncResult) +27 System.Web.Mvc.Controller.b__1d(IAsyncResult asyncResult, ExecuteCoreState innerState) +13 System. .Web.Mvc.Async.WrappedAsyncVoid_28_1.End() +54 System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +39 System.Web.Mvc.Controller.b__15(IAsyncResult asyncResult, контроллер контроллера) +12 System.Web.Mvc.Async.WrappedAsyncVoid_29_1.End() +54 System. Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult) +29 System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.EndExecute(IAsyncResult asyncResult) +10 System.Web.Mvc.MvcHandler.b__4(IAsyncResult asyncResult) , ProcessRequestState innerState) +21 System.Web.Mvc.Async.WrappedAsyncVoid_30_1.End() +54 System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +31 System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler. EndProcessRequest(результат IAsyncResult) +9 System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +9690172 System.Web.HttpApplication.ExecuteStep(шаг IExecutionStep, логическое значение и завершено синхронно) +155 - person James S; 27.05.2014