我使用的是ASP.MVC 5和EF6。我的目的是用来自另一个服务器的数据填充数据库,而不是阻塞用户界面。
数据库填充需要很多时间,大约10-15分钟。此时,用户可以使用系统进行操作。现在,他有几分钟非常严重的冰冻。因此,事实是,用户从库中加载数据并将任务加载数据一次性填充到数据库中。
我曾尝试将数据库填充代码放到另一个线程中,但没有帮助。当用户第一次登录时,他执行一些操作,开始填充数据库。执行此操作后,用户可以执行任何其他操作,并且界面不能被阻塞。
当用户使用系统时,他总是需要从我的数据库中加载一些数据。例如:当用户在1分钟内看到某个页面时,有10000个加载的数据,2分钟时有更多的数据,以此类推。
public ActionResult SomeAction()
{
new Thread(async () =>
{
Thread.CurrentThread.IsBackground = true;
await ImportTask();
}).Start();
... (some code)
return View();
}
public async Task ImportTask()
{
for (var i = 0; i < 180; i++)
{
using (var context = new ApplicationDBContext())
{
// synchronized data download with some sided library
var data = GetSomeDataFromAnotherServer(i);
foreach (var dataPart in data)
{
var stat = context.Data
.FirstOrDefault(x =>
x.EnumProperty == dataPart.EnumProperty &&
x.LongProperty == dataPart.LongProperty &&
x.DateTimeProperty == dataPart.DateTimeProperty)
?? new DataType()
{
EnumProperty = dataPart.EnumProperty,
LongProperty = dataPart.LongProperty,
DateTimeProperty == dataPart.DateTimeProperty
};
... (some another stat filling)
context.Statistics.AddOrUpdate(stat);
}
await context.SaveChangesAsync();
}
}
}还有另一个问题:我有能力一次下载大约10个线程的数据。如何修改此代码才能做到这一点?
附注:代码可以在此处包含一些拼写错误
发布于 2016-03-24 18:47:02
不要使用Thread类,它是一个古老的神秘的,难以理解/使用的应用程序接口,已经过时了99 %的用例。虽然在asp.net中也不要使用Task.Run,但更喜欢用它来做CPU受限的工作。当你从asp中窃取线程时,asp不能很好地处理你的问题,而且很容易造成死锁。
在处理真正的异步api (如DbContext.SaveChangesAsync())时,只需使用async/await,根本不用担心线程,它们在web上下文中不会给您带来任何性能提升,甚至会损害它(还会损害可伸缩性)。
发布于 2016-03-24 19:49:29
尝试:
public async Task<ActionResult> SomeAction()
{
await Task.Run(() => { ImportTask(); });
return View();
}
public async Task ImportTask()
{
using (var context = new ApplicationDBContext())
{
context.Configuration.AutoDetectChangesEnabled = false;
for (var i = 0; i < 180; i++)
{
var data = GetSomeDataFromAnotherServer(i);
foreach (var dataPart in data)
{
var stat = context.Data.FirstOrDefault(x => x.EnumProperty == dataPart.EnumProperty && x.LongProperty == dataPart.LongProperty && x.DateTimeProperty == dataPart.DateTimeProperty)
?? new DataType()
{
...
(some
another stat
filling)
context.Statistics.AddOrUpdate(stat);
}
}
await context.SaveChangesAsync();
}
}在for (var i = 0; i < 180; i++)中使用using (var context = new ApplicationDBContext())会导致180次DbContext的创建和处置操作。此外,对于批量插入,为了提高速度,您可以使用context.Configuration.AutoDetectChangesEnabled = false;或尝试这个库https://efbulkinsert.codeplex.com/
发布于 2016-03-24 22:01:10
您不需要在ASP.NET上下文中通过task.Run()创建原始线程或展开任务,因为这在ASP.NET上下文中主要是性能障碍。我也不会将其用于“一发即忘”的实现,因为它非常不可靠。如果你想着火,但忘记了,你可以考虑使用:HostingEnvironment.QueueBackgroundWorkItem,但我也不确定这是不是最好的方法。
您是否考虑过创建另一个进程来执行此操作,而不是在web请求过程中执行此操作?也许在服务器上运行的服务可以监视某人何时登录并执行数据移动?另一种选择可能是你从浏览器上的某个javascript调用这个数据移动操作来启动它?
https://stackoverflow.com/questions/36197959
复制相似问题