Очередь процессов 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);
}
}