Я сканирую каталог для поиска предметов.Я только что прочитал вопрос Многопоточная зацикливание каталогов в C # , но я все еще хочу сделать его многообработанным.Несмотря на то, что все говорят, что диск будет узким местом, у меня есть несколько моментов:
- Диски в основном могут быть «однопоточными», но как вы узнаете, что они собираются поднять в будущем?
- Как вы узнаете, что разные подпути, которые вы сканируете, являются одним и тем же физическим диском?
- Я использую уровень абстракции (даже два) поверх
System.IO
, чтобы впоследствии я мог повторно использовать код вразные сценарии.
Итак, моей первой идеей было использование Задача , и первой фиктивной реализацией было следующее:
public async Task Scan(bool recursive = false) {
var t = new Task(() => {
foreach (var p in path.scan) Add(p);
if (!recursive) return;
var tks = new Task[subs.Count]; var i = 0;
foreach (var s in subs) tks[i++] = s.Scan(true);
Task.WaitAll(tks);
}); t.Start();
await t;
}
Мне не нравится идея созданияTask
для каждого элемента, и, как правило, это не кажется идеальным, но это было только для теста, так как рекламируются задачи для автоматического управления потоками ...
Этот метод работает, но он очень медленный.Для завершения требуется более 5 с , в то время как приведенная ниже однопоточная версия занимает около 0,5 с для завершения всей программы с одним и тем же набором данных:
public void Scan2(bool recursive = false) {
foreach (var p in path.scan) Add(p);
if (!recursive) return;
foreach (var s in subs) s.Scan2(true);
}
Iбродить, что на самом деле не так с методом кулакМашина не загружена, использование CUP незначительно, накопитель в порядке ... Я попытался профилировать его с помощью NProfiler, он мне мало что говорит, кроме того, что программа постоянно находится на Task.WaitAll(tks)
.
Я также написал механизм подсчета с блокировкой потоков, который вызывается при добавлении каждого элемента.Может быть, в этом проблема?
#region SubCouting
public Dictionary<Type, int> counters = new Dictionary<Type, int>();
private object cLock = new object();
private int _sc = 0;
public int subCount => _sc;
private void inCounter(Type t) {
lock (cLock) {
if (!counters.ContainsKey(t)) counters.Add(t, 1);
counters[t]++;
_sc++;
}
if (parent) parent.inCounter(t);
}
#endregion
Но даже если потоки ожидают здесь, разве время выполнения не будет похоже на однопоточную версию, а не в 10 раз медленнее?
I 'Я не уверен, как подойти к этому.Если я не хочу использовать задачи, нужно ли мне управлять потоками вручную или уже есть какая-то библиотека, которая бы подходила для этой работы?