Предложения для выполнения async ввода / вывода с параллельной библиотекой задач
-
26-09-2019 - |
Вопрос
У меня есть несколько высокопроизводительных файлов передачи файлов, который я писал в C # с использованием модели Async Programming (APM) IDIOM (например, BeginRead
/EndRead
). Этот код считывает файл с локального диска и записывает его в сокет.
Для лучшей производительности на современном оборудовании важно сохранить более одной нерешенной операции ввода / вывода в полете, когда это возможно. Таким образом, я публикую несколько BeginRead
операции в файле, затем, когда вы завершаете, я называю BeginSend
на розетке, а когда это завершает, я делаю другой BeginRead
в файл. Детали немного сложнее, чем на высоком уровне, это идея.
У меня работает код, основанный на APM, но очень трудно следовать и, вероятно, имеет тонкие ошибки параллелизма. Я хотел бы использовать TPL для этого вместо этого. Я догадался Task.Factory.FromAsync
только что сделаю это, но есть поймать.
Все образцы ввода / вывода, которые я видел (наиболее особенно StreamExtensions
Класс в параллельных расширении дополнений) Предположим, что нужно прочитать, а затем одна запись. Это не будет работать так, как мне нужно.
Я не могу использовать что-то простое, как Parallel.ForEach
или расширение дополнений Task.Factory.Iterate
Поскольку задачи ASYNC ввода / вывода не тратят много времени на рабочей нити, поэтому параллель просто запускает еще одну задачу, что приведет к тому, что потенциально десятки или сотни в ожидании операций ввода-вывода; слишком много! Вы можете работать вокруг этого Wait
В ваших задачах, но это вызывает создание обрабатываемого события (объект ядра), а блокирующее ожидание по заданию Wait, которая связана с рабочей нити. Моя реализация на основе APM позволяет избежать обоих этих вещей.
Я играю по разным способам сохранить несколько операций по чтению / записи в полете, и мне удалось сделать это, используя продолжения, которые вызывают метод, который создает другую задачу, но это чувствует себя неловко, и определенно не чувствует идиоматический TPL.
Кто-нибудь еще боролся с такой проблемой с TPL? Какие-либо предложения?
Решение
Если вы беспокоитесь о слишком многих потоках, вы можете просто установить ParallelOptions.MaxDegreeOfParallelism
до приемлемого номера в вашем звонке Parallel.ForEach
.