几天前我尝试在我的磁盘上执行快速搜索,例如,属性,扩展,在文件内执行更改等等......
这个想法是为了避免大文件或带有大量文件的目录等的“延迟”而使其具有极少的限制/锁定... 我知道它与“最佳实践”相去甚远,因为我没有使用像“MaxDegreeOfParallelism”这样的东西或者使用“while(true)”的拉动循环
即使代码运行得非常快,因为我们有支持它的架构。
如果有人想检查发生了什么,我试图将代码转移到虚拟控制台项目。
class Program
{
static ConcurrentQueue<String> dirToCheck;
static ConcurrentQueue<String> fileToCheck;
static int fileCount; //
static void Main(string[] args)
{
Initialize();
Task.Factory.StartNew(() => ScanDirectories(), TaskCreationOptions.LongRunning);
Task.Factory.StartNew(() => ScanFiles(), TaskCreationOptions.LongRunning);
Console.ReadLine();
}
static void Initialize()
{
//Instantiate caches
dirToCheck = new ConcurrentQueue<string>();
fileToCheck = new ConcurrentQueue<string>();
//Enqueue Directory to Scan here
//Avoid to Enqueue Nested/Sub directories, else they are going to be dcan at least twice
dirToCheck.Enqueue(@"C:\");
//Initialize counters
fileCount = 0;
}
static void ScanDirectories()
{
String dirToScan = null;
while (true)
{
if (dirToCheck.TryDequeue(out dirToScan))
{
ExtractDirectories(dirToScan);
ExtractFiles(dirToScan);
}
//Just here as a visual tracker to have some kind an idea about what's going on and where's the load
Console.WriteLine(dirToCheck.Count + "\t\t" + fileToCheck.Count + "\t\t" + fileCount);
}
}
static void ScanFiles()
{
while (true)
{
String fileToScan = null;
if (fileToCheck.TryDequeue(out fileToScan))
{
CheckFileAsync(fileToScan);
}
}
}
private static Task ExtractDirectories(string dirToScan)
{
Task worker = Task.Factory.StartNew(() =>
{
try
{
Parallel.ForEach<String>(Directory.EnumerateDirectories(dirToScan), (dirPath) =>
{
dirToCheck.Enqueue(dirPath);
});
}
catch (UnauthorizedAccessException) { }
}, TaskCreationOptions.AttachedToParent);
return worker;
}
private static Task ExtractFiles(string dirToScan)
{
Task worker = Task.Factory.StartNew(() =>
{
try
{
Parallel.ForEach<String>(Directory.EnumerateFiles(dirToScan), (filePath) =>
{
fileToCheck.Enqueue(filePath);
});
}
catch (UnauthorizedAccessException) { }
}, TaskCreationOptions.AttachedToParent);
return worker;
}
static Task CheckFileAsync(String filePath)
{
Task worker = Task.Factory.StartNew(() =>
{
//Add statement to play along with the file here
Interlocked.Increment(ref fileCount);
//WARNING !!! If your file fullname is too long this code may not be executed or may just crash
//I just put a simple check 'cause i found 2 or 3 different error message between the framework & msdn documentation
//"Full paths must not exceed 260 characters to maintain compatibility with Windows operating systems. For more information about this restriction, see the entry Long Paths in .NET in the BCL Team blog"
if (filePath.Length > 260)
return;
FileInfo fi = new FileInfo(filePath);
//Add statement here to use FileInfo
}, TaskCreationOptions.AttachedToParent);
return worker;
}
}
问题: 如何检测到我已完成ScanDirectory? 一旦完成,我可以设法将一个String空或对文件队列排队,以退出它。 我知道如果我使用“AttachedToParent”,我可以在父任务上有一个完成状态,然后例如执行类似“ContinueWith(()=&gt; {/ SomeCode注意结束 / })” 但是仍然是父任务正在进行拉动并且陷入一种无限循环并且每个子语句都开始新的任务。
另一方面,我不能简单地在每个队列中测试“Count”,因为我可能会刷新文件列表和目录列表,但可能会有另一个任务称为“EnumerateDirectory()”。
我正在尝试找到某种“反应”解决方案,并避免在循环中使用一些“if()”,因为对于AsyncCall来说,这是一个简单的while(true){},所以80%的时间都没有检查。
PS:我知道我可以使用TPL Dataflow,我不是因为我知道,无论如何,在没有数据流的.net 4.5中我都坚持.net 4.0,因为TPL的改进很少,我仍然很好奇关于它答案 0 :(得分:1)
ConcurrentQueue<T>
BlockingCollection<T>
专门针对此类生产者/消费者场景而设计,并提供CompleteAdding方法,以便生产者可以通知消费者它已完成添加工作。