Здесь есть несколько проблем, но, похоже, ни одна из них не является причиной того, что inputQueue.Count
имеет ненулевое значение в конце. В любом случае я хотел бы указать на проблемы, которые я вижу.
var taskList = new List<Task>();
for (var i = 0; i < n_parallel_exit_nodes; i++) // create 100 threads only
{
taskList.Add(Task.Factory.StartNew(async () =>
{
await Run();
}, TaskCreationOptions.RunContinuationsAsynchronously));
}
Метод Task.Factory.StartNew
не понимает asyn c делегатов, поэтому, когда он вызывается с asyn c lambda в качестве аргумента возвращает вложенную задачу. В этом случае он возвращает Task<Task<string>>
. Вы сохраняете эту вложенную задачу в коллекции List<Task>
, что возможно потому, что тип Task<TResult>
наследуется от типа Task
, но при этом вы теряете возможность ждать завершения (и получаете результат) внутренней задачи. Вы держите только ссылку на внешнюю задачу. Чудесным образом это не является проблемой в этом случае (обычно это так), поскольку внешняя задача выполняет всю работу, а внутренняя задача практически ничего не делает (кроме использования потока пула потоков для возврата строки "Done"
, которая на самом деле не является где угодно).
Вы также не прикрепляете никаких продолжения к внешним задачам, поэтому флаг TaskCreationOptions.RunContinuationsAsynchronously
кажется избыточным.
// create 100 threads only
Вы не создаете 100 потоков, вы создать 100 задач. Эти задачи запланированы в ThreadPool
, который будет немедленно истощен, потому что задачи долго выполняются, и начнет вводить один новый поток каждые 500 мсек c, пока все запланированные задачи не будут назначены на поток.
var scrapeRequest = new ProductResearch_ProData();
inputQueue.TryTake(out scrapeRequest);
Здесь вы создаете экземпляр объекта типа ProductResearch_ProData
, который немедленно отбрасывается и становится пригодным для сбора мусора в следующей строке. Метод TryTake
вернет объект, извлеченный из сумки, или null
, если сумка пуста. Вы игнорируете возвращаемое значение метода TryTake
, которое вполне может быть false
, поскольку при этом мешок мог быть опорожнен другим работником, а затем переходите к scrapeRequest
, который может иметь нулевое значение, что приводит к в этом случае NullReferenceException
.
Стоит отметить, что вы извлекаете объект типа ProductResearch_ProData
из ConcurrentBag<Data>
, так что либо класс Data
наследуется от базового класса ProductResearch_ProData
, либо это ошибка транскрипции в коде.