我正在运行Parallel for循环,它最初运行时间=处理器数量并执行长时间运行操作。完成后的每个任务,检查更多任务,如果找到,再次调用自己。
以下是我的代码的样子:
static void Main(string[] args)
{
Int32 numberOfProcessors = Environment.ProcessorCount;
Parallel.For(0, numberOfProcessors, index => DoSomething(index, sqsQueueURL));
}
private async static Task DoSomething(int index, string queueURL)
{
var receiveMessageRequest = new ReceiveMessageRequest { QueueUrl = queueURL, WaitTimeSeconds = 20, MaxNumberOfMessages = 1, VisibilityTimeout = 1200 };
AmazonSQSClient sqsClient = new AmazonSQSClient(new AmazonSQSConfig { MaxErrorRetry = 4 });
var receiveMessageResponse = sqsClient.ReceiveMessage(receiveMessageRequest);
foreach (var msg in receiveMessageResponse.Messages)
{
PerformALongRunningTask......
//delete the message
DeleteMessageRequest deleteMessageRequest = new DeleteMessageRequest(queueURL, msg.ReceiptHandle);
AmazonSQSClient sqsDeleteClient = new AmazonSQSClient();
sqsDeleteClient.DeleteMessage(deleteMessageRequest);
//Do it again
DoSometing(index,queueURL)
}
}
我的结果非常难以预测。它永远不会完成所有任务。它在完成所有事情之前退出。
我在这里做错了什么?
更短的代码:
static Int32 TimesToLoop = 143;
static void Main(string[] args)
{
Int32 numberOfProcessors = Environment.ProcessorCount;
Parallel.For(0, numberOfProcessors, index => DoSomething(index));
Console.Read();
}
private async static Task DoSomething(int index)
{
if(TimesToLoop == 0)
{
return;
}
Console.WriteLine(index);
Interlocked.Decrement(ref TimesToLoop);
DoSomething(index++);
return;
}
答案 0 :(得分:3)
我现在看到各种问题:
Parallel.For
刚刚开始执行任务。它不会等待它们完成。它会等待DoSomething
方法调用返回,但是它们会返回代表异步操作的任务,这些操作可能无法同步完成。await
任务返回的任务 - 它几乎肯定应该。 可能想要创建在foreach
循环中创建的所有任务的集合,并一次性等待它们,或者它可能立即await
它们。我们无法说出来。修复第一部分的最简单方法可能是使用Task.WaitAll
代替Parallel.For
:
var tasks = Enumerable.Range(0, numberOfProcessors)
.Select(index => DoSomething(index, sqsQueueURL))
.ToList();
Task.WaitAll(tasks);
与Task.WhenAll
不同,Task.WaitAll
将阻止,直到完成所有指定的任务。请注意,如果任何任务需要在调用WaitAll
的线程上继续执行,这是不安全,正是因为它阻止了 - 但是如果这是一个控制台应用程序并且您是从初始线程重新调用它,你可以正常,因为延续将在线程池上执行。
答案 1 :(得分:1)
private async static Task DoSomething(int index, string queueURL)
{
...
foreach (var msg in receiveMessageResponse.Messages)
{
...
//Do it again
DoSometing(index,queueURL)
}
}
您正在递归地调用DoSomething
并且没有条件可以打破/退出它。它可能会导致stackoverflow并终止你的程序。