#c# #multithreading
#c# #многопоточность
Вопрос:
У меня есть два метода (в C #):
List<Pizza> CookPizza(List<Order>);
List<HappyCustomers> DeliverPizza(List<Pizza>);
Эти операции не имеют общих объектов (кроме пицц, которые передаются от одной к другой) и потокобезопасны. Выполнение каждого из них занимает несколько секунд, и каждый из них использует разные ресурсы (печь или автомобиль). Таким образом, я хочу запускать их одновременно.
Как мне организовать обработку потоков с учетом этих ограничений:
-
Я знаю все начальные заказы (скажем, у меня их 100 000). Заказ может состоять из нескольких пицц, и я не знаю, сколько пицц в любом заказе, пока эти пиццы не будут приготовлены. (странно, я знаю). Обычно в заказе содержится 1 пицца, но их может быть целых 10.
-
Количество активных пицц обычно не должно превышать 100. Сюда входят свежеприготовленные пиццы и пиццы, которые доставляются. Это мягкое ограничение, поэтому я могу его немного превысить (например, когда был приготовлен большой заказ). Жесткий предел, вероятно, ближе к 500.
-
Обе операции более эффективны, когда над ними много работы. Как правило, CookPizza наиболее эффективна, когда выдается не менее 20 заказов. Доставка пиццы наиболее эффективна, когда предоставляется не менее 50 пицц. То есть я увижу снижение производительности, если я предоставлю этим методам меньше элементов, чем эти суммы. Хорошо использовать меньше элементов, если это все, что осталось.
Основная проблема, с которой я сталкиваюсь, заключается в том, как методам может потребоваться ждать друг друга.
- DeliverPizza, возможно, придется подождать, пока CookPizza завершит 50.
- CookPizza, возможно, придется подождать DeliverPizza, чтобы уменьшить количество активных пицц до 100.
Комментарии:
1. Должны ли методы иметь эти подписи?
2. 1, если вы нажали на эту ссылку из-за слова ПИЦЦА
3. @jgauffin, нет. Что вы имеете в виду?
Ответ №1:
Для начала я бы подошел к этой проблеме, используя модель, основанную на событиях.
Допустим, у нас есть PizzaDispatcher
объект, которому отдаются приказы. Диспетчер начинает вызов CookPizza
с заданным количеством заказов из начального пустого состояния. Когда пицца приготовлена, CookPizza
функция уведомляет диспетчера о том, что пицца была приготовлена (возможно, с помощью обратного вызова, который вы предоставляете в качестве параметра). Когда доставляется пицца, DeliverPizza
функция делает то же самое.
PizzaDispatcher
Теперь будет иметь достаточно информации, чтобы решить, когда и сколько пицц следует сдать для приготовления или для доставки, на основе количества приготовленных пицц и ожидающих доставки.
Это можно реорганизовать для использования событий вместо обратных вызовов и т.д., Но я публикую это ради идеи, а не специфики реализации.
Ответ №2:
Вам нужен параллельный буфер — возможно, параллельная очередь, и вам может понадобиться несколько. Вы хотите одновременную очередь заказов. Вы вызываете CookOrder с одновременной очередью. Когда CookOrder возвращается, вы вызываете его снова с новым содержимым очереди. Здесь вы можете опубликовать только первые 100 элементов или что-то еще, если хотите. Здесь заказы эффективно распределяются по очереди, и CookOrder всегда выполняется. Затем вы снова повторяете процесс с пиццами.
Комментарии:
1. Я поддержал это, но … простое наличие потокобезопасной коллекции на самом деле не помогает с сигнализацией, которую мне нужно выполнить.
Ответ №3:
Похоже, все, что вам нужно, — это PizzaManager
который решает, какой Pizza
заказ приготовить первым, а затем передает их DeliveryBoy
для доставки. Затем, как только DeliveryBoy
DeliversPizza
, он сообщает обратно PizzaManager
, чтобы получить следующий Pizza
заказ. PizzaManager
выполняет всю математику, связанную с оптимизацией приоритета того, какие заказы готовить и доставлять. DeliveryBoy
Вероятно, PizzaManager
в качестве delegate
было бы.
Ответ №4:
одна мысль
добавьте переменную-член в Pizza, чтобы отслеживать is_cooked . затем во время CookPizza установите для этого элемента значение true, когда закончите, затем во время DeliverPizza проверьте этот элемент, прежде чем продолжить.
Комментарии:
1. Я думаю, лучше отслеживать состояние пиццы по тому, в какой очереди она находится. При доставке просто удалите объект pizza или поместите в очередь доставки.