Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/grails/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# MVC-并行任务中的System.Threading.ThreadAbortException_C#_.net_Asp.net Mvc_Multithreading_Entity Framework - Fatal编程技术网

C# MVC-并行任务中的System.Threading.ThreadAbortException

C# MVC-并行任务中的System.Threading.ThreadAbortException,c#,.net,asp.net-mvc,multithreading,entity-framework,C#,.net,Asp.net Mvc,Multithreading,Entity Framework,在我的MVC应用程序中,超级管理员可以设置任务队列,例如更新数据库。因此,当管理员向队列添加更新时,控制器将启动一个在后台工作的新任务。但是,当您添加一些任务时,应用程序会抛出System.Threading.ThreadAbortException:线程被中止。此外,堆栈跟踪表明它发生在代码的不同行上 我还应该补充一点,任务使用EF6实体与SQL server一起工作,根据堆栈跟踪,它发生在对数据库执行操作之后或同时。由于更新通常很大,我使用db.Configuration.AutoDetec

在我的MVC应用程序中,超级管理员可以设置任务队列,例如更新数据库。因此,当管理员向队列添加更新时,控制器将启动一个在后台工作的新任务。但是,当您添加一些任务时,应用程序会抛出
System.Threading.ThreadAbortException:线程被中止
。此外,堆栈跟踪表明它发生在代码的不同行上

我还应该补充一点,任务使用EF6实体与SQL server一起工作,根据堆栈跟踪,它发生在对数据库执行操作之后或同时。由于更新通常很大,我使用
db.Configuration.AutoDetectChangesEnabled=false
并每隔20k行手动保存更改,处理和重新创建数据库

堆栈跟踪的示例:

2015年7月15日星期三下午5:18:36:[报告]异常(第4566667行;第6节):System.Threading.ThreadAbortException:线程被中止。 在System.Array.Copy(数组源数组、Int32源索引、数组目标数组、Int32目标索引、Int32长度、布尔可靠) at System.Collections.Generic.List`1.set_容量(Int32值) 位于System.Data.Entity.Core.Metadata.Edm.MetadataCollection`1.SetReadOnly() at System.Data.Entity.Core.Metadata.Edm.TypeUsage..ctor(EdmType EdmType,IEnumerable`1 facets) 位于System.Data.Entity.Core.Common.CommandTrees.DbExpression..ctor(DbExpressionKind kind,TypeUsage type,Boolean forceNullable) 位于System.Data.Entity.Core.Common.CommandTrees.ExpressionBuilder.DbExpressionBuilder.PropertyFromMember(DbExpression实例,EdmMember属性,字符串propertyArgumentName) 位于System.Data.Entity.Core.Mapping.Update.Internal.UpdateCompiler.GenerateEqualityExpression(DbExpressionBinding目标、EdmProperty属性、PropagatorResult值) 位于System.Data.Entity.Core.Mapping.Update.Internal.UpdateCompiler.BuildPredicate(DbExpressionBinding目标、PropagatorResult referenceRow、PropagatorResult current、TableChangeProcessor处理器、Boolean&rowMustBeTouched) 位于System.Data.Entity.Core.Mapping.Update.Internal.UpdateCompiler.BuildUpdateCommand(PropagatorResult oldRow、PropagatorResult newRow、TableChangeProcessor处理器) 位于System.Data.Entity.Core.Mapping.Update.Internal.TableChangeProcessor.CompileCommand(ChangeNode ChangeNode,UpdateCompiler编译器) 在System.Data.Entity.Core.Mapping.Update.Internal.UpdateTranslator.d_ua.MoveNext()中 在System.Linq.Enumerable.d_u71`1.MoveNext()中 位于System.Data.Entity.Core.Mapping.Update.Internal.UpdateCommandOrderer..ctor(IEnumerable`1命令,UpdateTranslator转换器) 位于System.Data.Entity.Core.Mapping.Update.Internal.UpdateTranslator.ProduceCommands()处 位于System.Data.Entity.Core.Mapping.Update.Internal.UpdateTranslator.Update()处 在System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 Func,IDBEcutionStrategy executionStrategy,Boolean startLocalTransaction,Boolean releaseConnectionOnSuccess) 位于System.Data.Entity.Core.Objects.ObjectContext.SaveChangesToStore(SaveOptions选项、IDBEcutionStrategy executionStrategy、Boolean startLocalTransaction) 在System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1操作)中 位于System.Data.Entity.Core.Objects.ObjectContext.SaveChangesInternal(SaveOptions选项,布尔值executeInExistingTransaction) 位于System.Data.Entity.Internal.InternalContext.SaveChanges()处 在MyWebsite.Controllers.AdminPanelController.ApplyUpdate(字符串文件路径、HttpApplicationStateBase上下文、Int32保存间隔、布尔校验重复、字符串冲突)


有什么我可能做错的吗?

我想这可能与IIS空闲状态有关。您可以尝试每隔几分钟从另一个空闲线程使用基于自身的请求保持IIS运行后台线程。它将防止IIS中止另一个后台长时间运行的线程。每10分钟进行自我请求的方法示例:

public void KeepIisBackgroundThreadsAlive(Object stateInfo) {
    while (true) {
        var serverOwnIp = Dns.GetHostEntry(Dns.GetHostName()).AddressList.First(o => o.AddressFamily == AddressFamily.InterNetwork).ToString();
        var req = (HttpWebRequest) WebRequest.Create(new Uri("http://" + serverOwnIp));
        req.Method = "GET";
        var response = (HttpWebResponse) req.GetResponse();
        var respStream = response.GetResponseStream();
        var delay = new TimeSpan(0, 0, 10, 0);
        Thread.Sleep(delay);
    }
}
然后,您可以在Application Started方法的Global.asax.cs中使用ThreadPool.QueueUserWorkItem方法启动此方法:

protected override void OnApplicationStarted(){
    ThreadPool.QueueUserWorkItem(KeepIisBackgroundThreadsAlive)
}
重要更新

发现此方法仅适用于已禁用的IIS应用程序池回收。若您不熟悉此IIS功能,请仔细阅读本文。 请注意,你应该100%确定你在做什么


若你们在并没有关闭回收的情况下使用这种方法,你们可能会面临在第一次回收发生后网站不会启动的严重错误。对于这些需要应用程序池回收的网站,我强烈建议将长时间运行的作业移动到不依赖IIS的单独服务中(如果您使用Azure Web角色-至少移动到单独的工作者角色实例中).

我认为,通过正确地将此功能抽象到另一个应用程序(更具体地说是Windows服务),从长远来看,您将获得更积极的结果。在我的公司,我编写了一个守护程序,它有长期运行/轮询的工作人员,它已经成为我们技术堆栈的重要组成部分4年多了。 这看起来像是一份工作日志,但它会回报你红利

顺便说一句,你所面临的实际问题;我同意@Vova的观点,因为您的应用程序是在IIS中托管的,IIS会做很多事情来确保您的应用程序不会导致服务器的其余部分停机。其中一些可能包括线程的终止

这里有几个链接,人们正在讨论你的问题(谷歌一点,你会发现更多):

编辑: 我想我应该为那些感兴趣的人详细介绍一下这个守护进程服务的体系结构

基本上它不太复杂,但非常有效。它由“worker”类组成,这些类做一些事情。负载平衡类管理所有instanc