Я новичок в мире С#.Net и создаю службу.NET API, которая записывает в таблицу базы данных MS Access, которая выполняет полные блокировки таблиц, одновременно будет записываться до 20 человек (мы избавиться от Access, но не скоро!). Мы должны обеспечить, чтобы "писатели" не блокировались.
Хотя многопотоковое решение будет работать на большинстве языков, Apple рекомендует использовать диспетчерские очереди для поддержки проблем параллелизма, таких как выше (см. Выдержку ниже), где запросы на общий ресурс помещаются в очередь и обрабатываются по одному за раз, чтобы избежать конфликтов.
Есть ли эквивалентный подход или идиома в С#?
Я действительно видел этот вопрос, но на самом деле у меня не было ответа в правильном контексте, который мне нужен.
Больше подробностей:
Выдержка из диспетчерских очередей Документы Objective-C:
Очереди отправки - это механизм на основе C для выполнения пользовательских задач. Очередь отправки выполняет задачи как последовательно, так и одновременно, но всегда в порядке ввода-вывода. (Другими словами, очередь отправки всегда деактивирует и запускает задачи в том же порядке, в котором они были добавлены в очередь.) В очереди последовательной диспетчеризации выполняется только одна задача за раз, ожидая завершения этой задачи перед тем, как выполнить деинструмент и запустить новый. Напротив, параллельная очередь отправки запускает столько задач, сколько может, не дожидаясь завершения уже начатых задач.
Очереди отправки имеют другие преимущества:
Они обеспечивают простой и простой интерфейс программирования. Они предлагают автоматическое и целостное управление пулами потоков. Они обеспечивают скорость настроенной сборки. Они намного эффективнее с точки зрения памяти (поскольку стеки потоков не задерживаются в памяти приложения). Они не попадают в ядро под нагрузкой. Асинхронная диспетчеризация задач в очереди отправки не может заблокировать очередь. Они грациозно расходятся в споре. Серийные очереди отправки предлагают более эффективную альтернативу замкам и другим примитивам синхронизации.
Задачи, которые вы отправляете в очередь отправки, должны быть инкапсулированы внутри любой функции или блочного объекта
EDIT: Оказывается, что.Net "Main Loop" или основной поток - это то, где вы можете делать запросы на обработку вашего кода. Основной цикл - это то, где обычно выполняется весь пользовательский интерфейс. В соответствии с этим вопросом SO Главный контур Windows GUI в С#... где он? Вы также можете получить доступ к нему через Application.Run и Timer
Я нашел ваш вопрос интересным и связанным с областью.NET Framework, я мог бы использовать больше знаний, поэтому я сделал небольшое исследование по этой теме. Ну вот:
Существует несколько вариантов.NET, связанных с дружескими управляющими потоками, которые могут помочь с тем, что вы пытаетесь сделать. TaskScheduler.QueueTask
являются TaskScheduler.QueueTask
и ThreadPool.QueueUserWorkItem
. BackgroundWorker
также, возможно, применим к вашей архитектурно незавидной ситуации.
Ни в документации для TaskScheduler
ни в ThreadPool
задачи /TaskScheduler
очереди не упоминается любая гарантия порядка заказов в очереди. Если порядок ваших многопоточных задач очень важен, основанный на моих, по общему признанию, ограниченных знаниях платформы.NET, вы можете захотеть гарантировать, что очередь выполняется с помощью стартового метода очереди, который принимает запросы на запись и записывает в базу данных или ставит в очередь запись пока права на запись не будут доступны. Это будет немного грязно, потому что вам нужно будет блокировать параллелизм. Этот github-хостинг код из аналогичного вопроса SO может быть хорошим для этого. Я его не тестировал.
В качестве альтернативы вы можете ставить в очередь задачи записи в пул потоков, ограниченный одним потоком за один раз, используя SetMaxThreads
. У меня нет гарантий, что это подходит для вашей ситуации или когда-либо, хотя это кажется простым.
надеюсь, это поможет
EDIT: Дальнейшие исследования аналогичного SO-вопроса, отмеченные оригинальным вопросником, Concurrent Queue, новый с.NET 4.0, обеспечивают обработку следующей задачи из задач с ConcurrentQueue
без дополнительного кода блокировки параллелизма, необходимого для обычной Queue
были использованы. Такой подход позволил бы одновременно выполнять несколько задач, а не всегда, ожидая завершения предыдущей задачи, как в потоке пула потоков нитевого процессора.