在完成之前停止介于两者之间的for循环
本文关键字:两者之间 for 循环 | 更新日期: 2023-09-27 18:24:26
我们正在asp.net c#项目中使用Solrnet将文档索引到Solr中。我们有不能使用Solr DIH的要求,所以我们使用以下代码将某些批次的产品索引到Solr:
decimal cycleCount = ProductCount / batchSize;
for (int i = 0; i <= Math.Round(cycleCount); i++)
{
var Products = Products(batchSize, languageId, storeId).ToList();
solrCustomWorker.Add(solrProducts);
solrCustomWorker.Commit();
}
由于文档大小巨大,完成整个过程需要花费大量时间(大多数情况下需要几个小时),有时我们需要通过手动干预来停止这一过程。
然而,我不知道如何在完成之前停止这一索引批处理周期。具有大批量文档的单个周期需要几秒钟才能完成,然后提交。但考虑到大量的文档,在执行完整索引时需要几个小时,我们无法在此期间停止这一过程。
有什么想法吗?我该如何在两者之间停止这个过程。。我不知道这里该怎么办?
请提出建议。
这里可以采用的两种方法是:
1使用全局变量(不过这不是一个好的解决方案,希望原因很明显):
public static bool KeepRunning;
...
for (int i = 0; i <= Math.Round(cycleCount); i++)
{
if (KeepRunning)
{
var Products = Products(batchSize, languageId, storeId).ToList();
solrCustomWorker.Add(solrProducts);
solrCustomWorker.Commit();
}
}
2使用回调检查是否继续运行:
public void SomeMethod(Func<bool> keepRunning)
{
for (int i = 0; i <= Math.Round(cycleCount); i++)
{
if (keepRunning())
{
var Products = Products(batchSize, languageId, storeId).ToList();
solrCustomWorker.Add(solrProducts);
solrCustomWorker.Commit();
}
}
}
第二种方法的优点是将决策逻辑与索引逻辑解耦,并避免全局变量,例如,通过捕获是否在对长时间运行的进程和事件处理程序的异步调用的闭包内继续运行。
另一种可能有点迂回的方法是创建一个应用程序文件"Global.asax",并尝试使用这里描述的后台工作程序。你也可以在这里查看我的winforms示例
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Threading;
using System.Web;
using System.Web.Security;
using System.Web.SessionState;
namespace AspNetBackgroundProcess
{
public static BackgroundWorker worker = new BackgroundWorker()
public static bool stopWorker = false;
public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
worker.DoWork += new DoWorkEventHandler(DoWork);
worker.WorkerReportsProgress = true;
worker.WorkerSupportsCancellation = true;
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(WorkerCompleted);
// Calling the DoWork Method Asynchronously
worker.RunWorkerAsync();
}
protected void Application_End(object sender, EventArgs e)
{
if (worker != null)
worker.CancelAsync();
}
//Start Process
private void button1_Click(object sender, EventArgs e)
{
worker.RunWorkerAsync();
}
//Cancel Process
private void button2_Click(object sender, EventArgs e)
{
//Check if background worker is doing anything and send a cancellation if it is
if (worker.IsBusy)
{
worker.CancelAsync();
}
}
private static void DoWork(object sender, DoWorkEventArgs e)
{
decimal cycleCount = ProductCount / batchSize; //Depending on where you get these variables, you might consider moving this to the class level along with the other variable declarations
for (int i = 0; i <= Math.Round(cycleCount); i++)
{
//Check if there is a request to cancel the process
if (worker.CancellationPending)
{
e.Cancel = true;
worker.ReportProgress(0);
return;
}
var Products = Products(batchSize, languageId, storeId).ToList();
solrCustomWorker.Add(solrProducts);
solrCustomWorker.Commit();
}
}
private static void WorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
if (worker != null)
{
System.Threading.Thread.Sleep(3000);
if (!stopWorker)
{
worker.RunWorkerAsync();
}
else
{
while (stopWorker)
{
Thread.Sleep(6000);
}
worker.RunWorkerAsync();
}
}
}
}
}