Очередь процессов c многопоточностью или задачами

у меня есть приложение телефонии сообщение, в котором есть много много сообщений для обработки.Поскольку телефонные порты ограничены, сообщение будет обработано первым в первом выходе. Каждое сообщение имеет флаг "подтвердить", который указывает на то, что обрабатывается. Конечно, он был инициализирован как false.

Я хочу поместить все сообщения в очередь, а затем обработать их несколькими потоками или задачами.

    public class MessageQueue
    {
        public Queue MessageWorkItem { get; set; }
        public Messages Message { get; set; }
        public MessageQueue()
        {
            MessageWorkItem = new Queue();
            Message = new Messages();
        }
        public void GetMessageMetaData()
        {
            try
            {
                // It is just a test, add only one item into the queue
                Message.MessageID = Guid.NewGuid();
                Message.NumberToCall = "1111111111";
                Message.FacilityID = "3333";
                Message.NumberToDial = "2222222222";
                Message.CountryCode = "1";
                Message.Acknowledge = false;
            }
            catch (Exception ex)
            {
            }
        }

        public void AddingItemToQueue()
        {
            GetMessageMetaData();
            if (!Message.Acknowledge)
            {
                lock (MessageWorkItem)
                {
                    MessageWorkItem.Enqueue(Message);
                }
            }
        }
    }

    public class Messages
    {
        public Guid MessageID { get; set; }
        public string NumberToCall { get; set; }
        public string FacilityID { get; set; }
        public string NumberToDial { get; set; }
        public string CountryCode { get; set; }
        public bool Acknowledge { get; set; }
    }

теперь мой вопрос заключается в том, как удалить элемент из очередь с многопоточностью. Для каждого элемента из очереди я хочу запустить сценарий.

        public void RunScript(Message item)
        {
            try
            {
                PlayMessage(item); 
                return;
            }
            catch (HangupException hex)
            {
                Log.WriteWithId("Caller Hungup!", hex.Message);
            }
            catch (Exception ex)
            {
                Log.WriteException(ex, "Unexpected exception: {0}");
            }
        }

что я думал, чтобы увидеть, если

if(MessageWorkItem.Количество >= 1) Тогда что-то делаю, но мне нужна помощь кода.

2 ответов


если вы можете использовать .Net 4.5, я бы предложил посмотреть на поток данных из параллельной библиотеки задач (TPL).

эта страница приводит к множеству примеров пошаговых руководств, таких как как: реализовать шаблон потока данных производитель-потребитель и использование данных в приложениях Windows.

взгляните на эту документацию, чтобы узнать, поможет ли она вам. Это довольно много, но я думаю, что это, вероятно, будет ваш наилучший подход.

кроме того, вы можете изучить использование BlockingCollection вместе с GetConsumingEnumerable() метод доступа к элементам в очереди.

то, что вы делаете, это разделить работу на объекты, которые вы хотите обработать каким-то образом, и использовать BlockingCollection для управления очередью.

некоторые примеры кода с помощью ints вместо объектов в качестве рабочих элементов поможет продемонстрировать это:

когда рабочий поток закончил с ним текущий элемент, он удалит новый элемент из рабочей очереди, обработает этот элемент, а затем добавит его в выходную очередь.

отдельный поток потребителей удаляет завершенные элементы из очереди вывода и что-то с ними делает.

в конце мы должны ждать, пока все рабочие закончат (задача.WaitAll (workers)) прежде чем мы сможем отметить очередь вывода как завершенную (outputQueue.CompleteAdding ()).

using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;

namespace Demo
{
    class Program
    {
        static void Main(string[] args)
        {
            new Program().run();
        }

        void run()
        {
            int threadCount = 4;
            Task[] workers = new Task[threadCount];

            Task.Factory.StartNew(consumer);

            for (int i = 0; i < threadCount; ++i)
            {
                int workerId = i;
                Task task = new Task(() => worker(workerId));
                workers[i] = task;
                task.Start();
            }

            for (int i = 0; i < 100; ++i)
            {
                Console.WriteLine("Queueing work item {0}", i);
                inputQueue.Add(i);
                Thread.Sleep(50);
            }

            Console.WriteLine("Stopping adding.");
            inputQueue.CompleteAdding();
            Task.WaitAll(workers);
            outputQueue.CompleteAdding();
            Console.WriteLine("Done.");

            Console.ReadLine();
        }

        void worker(int workerId)
        {
            Console.WriteLine("Worker {0} is starting.", workerId);

            foreach (var workItem in inputQueue.GetConsumingEnumerable())
            {
                Console.WriteLine("Worker {0} is processing item {1}", workerId, workItem);
                Thread.Sleep(100);          // Simulate work.
                outputQueue.Add(workItem);  // Output completed item.
            }

            Console.WriteLine("Worker {0} is stopping.", workerId);
        }

        void consumer()
        {
            Console.WriteLine("Consumer is starting.");

            foreach (var workItem in outputQueue.GetConsumingEnumerable())
            {
                Console.WriteLine("Consumer is using item {0}", workItem);
                Thread.Sleep(25);
            }

            Console.WriteLine("Consumer is finished.");
        }

        BlockingCollection<int> inputQueue = new BlockingCollection<int>();
        BlockingCollection<int> outputQueue = new BlockingCollection<int>();
    }
}

параллельный.По каждому элементу С TPL. Она параллельна для каждого.

пример (изменен MessageWorkItem на общую очередь):

    public class MessageQueue
{
    public Queue<Message> MessageWorkItem { get; set; }

    public MessageQueue()
    {
        MessageWorkItem = new Queue<Message>();
    }

    public Message GetMessageMetaData()
    {
        try
        {
            // It is just a test, add only one item into the queue
            return new Message()
            {
                MessageID = Guid.NewGuid(),
                NumberToCall = "1111111111",
                FacilityID = "3333",
                NumberToDial = "2222222222",
                CountryCode = "1",
                Acknowledge = false
            };
        }
        catch (Exception ex)
        {
            return null;
        }
    }

    public void AddingItemToQueue()
    {
        var message = GetMessageMetaData();
        if (!message.Acknowledge)
        {
            lock (MessageWorkItem)
            {
                MessageWorkItem.Enqueue(message);
            }
        }
    }
}

public class Message
{
    public Guid MessageID { get; set; }
    public string NumberToCall { get; set; }
    public string FacilityID { get; set; }
    public string NumberToDial { get; set; }
    public string CountryCode { get; set; }
    public bool Acknowledge { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        MessageQueue me = new MessageQueue();
        for (int i = 0; i < 10000; i++)
            me.AddingItemToQueue();

        Console.WriteLine(me.MessageWorkItem.Count);

        Parallel.ForEach(me.MessageWorkItem, RunScript);
    }

    static void RunScript(Message item)
    {
        // todo: ...
        Console.WriteLine(item.MessageID);
        Thread.Sleep(300);
    }
}