尝试将AddMessage批量处理到Azure队列

时间:2014-04-07 03:53:35

标签: multithreading azure queue batch-processing

我希望将大约50K消息添加到azure队列中。

我不确定我的代码是否安全。感觉/闻起来很糟糕。

基本上,给出POCO的集合,将POCO序列化为某个json,然后将该json文本添加到队列中。

public void AddMessage(T content)
{
    content.ShouldNotBe(null);

    var json = JsonConvert.SerializeObject(content);
    var message = new CloudQueueMessage(json);
    Queue.AddMessage(message);
}

public void AddMessages(ICollection<T> contents)
{
    contents.ShouldNotBe(null);
    Parallel.ForEach(contents, AddMessage);
}

有人可以告诉我应该做些什么来解决这个问题 - 最重要的是,为什么?

在这种情况下,我觉得队列可能不是线程安全的。

4 个答案:

答案 0 :(得分:4)

我观察到的有关Parallel.ForEach和处理Azure存储的一些事情(我的经验是并行上传blob /块):

  • Azure存储操作是基于网络(IO)的操作,而不是处理器密集型操作。如果我没弄错的话,Parallel.ForEach更适合处理器密集型应用程序。
  • 我们注意到使用Parallel.ForEach上传大量blob(或块)的另一件事是我们开始获得大量Timeout异常并且实际上减慢了整个操作。我相信这样做的原因是当你使用这种方法迭代包含大量项目的集合时,你基本上将控制权交给底层框架来决定如何处理该集合。在这种情况下,会发生很多Context Switching,从而减​​慢操作速度。考虑到有效载荷较小,不确定这在你的场景中是如何工作的。

我的建议是让应用程序控制它可以产生的并行线程数。一个好的标准是逻辑处理器的数量。另一个好的标准是IE可以打开的端口数量。所以你会产生那么多并行线程。然后,您可以等待所有线程完成以生成下一组并行线程,或者在一个任务完成后立即启动新线程。

伪代码:

    ICollection<string> messageContents;
    private void AddMessages()
    {
        int maxParallelThreads = Math.Min(Environment.ProcessorCount, messageContents.Count);
        if (maxParallelThreads > 0)
        {
            var itemsToAdd = messageContents.Take(maxParallelThreads);
            List<Task> tasks = new List<Task>();
            for (var i = 0; i < maxParallelThreads; i++)
            {
                tasks.Add(Task.Factory.StartNew(() =>
                {
                    AddMessage(itemsToAdd[i]);
                    RemoveItemFromCollection();
                }));
            }
            Task.WaitAll(tasks.ToArray());
            AddMessages();
        }
    }

答案 1 :(得分:2)

您的代码在我看来很高级。 Gaurav的添加有意义,因此您可以更好地控制请求的并行处理。确保添加某种形式的重试逻辑,并可能将DefaultConnectionLimit设置为大于其默认值(即2)的值。如果您遇到一种限制形式,您还可以考虑在多个存储帐户中添加多个Azure队列,具体取决于您获得的错误类型。

答案 2 :(得分:0)

对于任何想要批量/批量添加大量非POCO /字符串消息到队列的人来说,备用/更好的解决方案是将消息列表添加为单个消息或blob,然后在queue / blob trigger traverse&amp;将每条消息添加到[单独]队列。

答案 3 :(得分:-1)

var maxDegreeOfParallelism = Math.Min(Environment.ProcessorCount,cloudQueueMessageCollection.Count());
var parallelOptions=new ParallelOptions { MaxDegreeOfParallelism = maxDegreeOfParallelism };
Parallel.ForEach(cloudQueueMessageCollection, parallelOptions,
                    async (m) => await AddMessageAsync(queue, connectionStringOrKey, m));