我有一个大型数据库,我使用Entity Framework访问它。我将所有项目都设为List<Item>
。当我在循环中处理它们时:
List<Item> lstItems = UnitOfWork.Items.GetAllAsync(); // repository pattern and Unit Of Work patterns
foreach (Item item in lstItems)
{
//do something with the item
}
我需要的是,如果其中一个项目在循环中处理失败,我希望能够在此循环中忽略它之前重试该操作3次。此外,我不希望循环刹车,因此无论项目处理是成功还是失败,循环都应该继续,直到列表中的最后一项。
我可以用于此目的的模式吗?
我正在考虑使用try catch,如果处理失败,那么在catch部分将其添加到名为List<Item>
的新processAgain
中,一旦主列表完成处理,然后处理{{1} } list。
答案 0 :(得分:2)
由于您希望实现并行处理,因此使用Task
和异步处理将是一种很好的方法。
因此,您需要定义一个将成为Task
/ Action
的方法或表达式,并在内部包含重试模式:
public const int MAX_RETRY_COUNT = 3;
private void ProcessItemsAsync(Item item, int retryCount)
{
// Note: Exceptions thrown here will pop up
// as AggregateException in Task.WaitAll()
if (retryCount >= MAX_RETRY_COUNT)
throw new InvalidOperationException(
"The maximum amount of retries has been exceeded");
retryCount++;
// Either implement try-catch, or use conditional operator.
try
{
// Do stuff with item
}
catch(Exception ex)
{
// Exception logging relevant? If not, just retry
ProcessItemsAsync(item, retryCount);
}
}
定义Task
方法后,您可以一次处理大量任务:
public const int BULK_AMOUNT = 10;
private async void ProcessSqlData()
{
List<Item> lstItems = await UnitOfWork.Items.GetAllAsync();
for (var i = 0; i < lstItems.Count; i += BULK_AMOUNT)
{
// Running the process parallel with to many items
// might slow down the whole process, so just take a bulk
var bulk = lstItems.Skip(i).Take(BULK_AMOUNT).ToArray();
var tasks = new Task[bulk.Length];
for (var j = 0; j <= bulk.Length; j++)
{
// Create and start tasks, use ProcessItemsAsync as Action
tasks[j] = Task.Factory.StartNew(() => ProcessItemsAsync(bulk[j], 0));
}
// Wait for the bulk to complete
try
{
Task.WaitAll(tasks);
}
catch (AggregateException e)
{
Log.WriteLine(String.Format(
"The maximum amount of retries has been exceeded in bulk #{0}. Error message: {1}",
i,
e.InnerException != null
? e.InnerException.Message
: e.Message));
}
}
}
但是,如果您知道运行此计算机的计算机具有足够的性能,则可能会增加BULK_AMOUNT
。你应该测试它,在这里找到最佳数量。
答案 1 :(得分:0)
您可以使用生成器/消费者模式,如here
在从队列中删除项目之前,只需在Consume方法中创建处理逻辑(重试三次)
答案 2 :(得分:0)
我建议使用递归方法:
static int errorCounter;
static void Main(string[] args)
{
List<Item> lstItems = new List<Item>();
foreach (var item in lstItems)
{
errorCounter = 0;
bool succesful = CustomAction(item);
}
}
static bool CustomAction(Item item)
{
try
{
//your custom actions with the item
}
catch (Exception ex)
{
if (errorCounter < 3)
{
errorCounter++;
CustomAction(item);
}
else
{
return false;
}
}
return true;
}
编辑:如果由于任何原因你不想使用静态计数器,你也可以在Main方法中初始化计数器并将其作为参数传递给CustomAction
答案 3 :(得分:0)
您可以尝试使用递归。这样的事情:
List<Item> lstItems = UnitOfWork.Items.GetAllAsync(); // repository pattern and Unit Of Work patterns
foreach (Item item in lstItems)
{
YourProcessingFunction(yourArgs, int count);
}
在你的处理函数中(你的Args,int count):
try
{
if(count<3)
{
//Processing
return someValue;
}
else
{
return;
}
}
catch(Exception ex)
{
return YourProcessingFunction(yourArgs, int count);
}
答案 4 :(得分:0)
不需要递归,因为它会使你的逻辑变得复杂。您可以使用try catch块,如下所示
List<Item> lstItems = UnitOfWork.Items.GetAllAsync(); // repository pattern and Unit Of Work patterns
foreach (Item item in lstItems)
{
try
{
//do something with the item
}
catch(Exception ex)
{
for(int i = 1; i <= 3; i++)
{
// do something with the item
}
// to continue external loop
continue;
}
}
我希望它会有所帮助:)。