Tell me how to better organize the interaction of the two threads with a recursive traversal of directories? Suppose the first stream recursively walks around these same directories, and the second, receiving information from the first stream (say via the collection), enters these directories into an element on the form (TreeView).
- It is best to do it "somehow" (preferably reading something on the Internet before), after which, if the result is not satisfactory, contact the appropriate resource (not SO) with a request to optimize the code. - Regent
- It is better not to go around recursively: stackoverflow.com/a/2107294/1985167 , plus see the speed comparison in the question itself. - andreycha
- almost doubled you can speed up traversal if you use WinAPI. c # example here - Stack
2 answers
What is the point of parallelizing the fact that in one thread it will run faster due to a more linear access to the disk?
You can try to make in one stream receiving, and in another - output to formk.
It is possible to start processing in parallel streams for different physical (!) Disks.
Well and it is necessary to bypass directories most recursively with access exception handling.
- The author of the question does not speak about parallelization of the traversal. And about the interaction of two threads - one passes, the other displays. - andreycha
- "in one stream it will work faster due to more linear disk access" - is this rule applicable to SSD? - Stack
- @Stack, I do not know. At the time of measurement ssd no one else had. If there is, you can check and say. - Qwertiy ♦
To solve problems in which one of the streams is a data provider (bypasses directories), and the second is a consumer (displays directory names on a form), you can use the ConcurrentQueue<T> . For example:
public partial class Form1 : Form { private readonly ConcurrentQueue<string> _dirsQueue = new ConcurrentQueue<string>(); private volatile bool _enumerationEnded; public Form1() { InitializeComponent(); } private void EnumerateDirsButton_Click(object sender, EventArgs e) { _enumerationEnded = false; new Thread(EnumerateDirs).Start(); new Thread(ShowDirs).Start(); } private void ShowDirs() { while (!_enumerationEnded || _dirsQueue.Count != 0) { string dir; if (_dirsQueue.TryDequeue(out dir)) { InvokeInUIThread(DirsListBox, () => DirsListBox.Items.Add(dir)); } } } private void EnumerateDirs() { try { EnumerateDirs("c:\\"); _enumerationEnded = true; } catch (Exception exception) { // handle exception } } private void EnumerateDirs(string path) { try { var dirs = Directory.EnumerateDirectories(path); foreach (var dir in dirs) { _dirsQueue.Enqueue(dir); EnumerateDirs(dir); } } catch (Exception exception) { // handle exception } } private void InvokeInUIThread(Control control, Action action) { if (control.InvokeRequired) { control.Invoke(action); } else { action(); } } } In this case, when crawling directories, you must take into account access rights and handle appropriate exceptions. A good example of traversing the directory tree can be found here . I also want to note that access to the Windows Forms element is possible only from the thread in which this element is created, therefore the InvokeInUIThread method is InvokeInUIThread .
In this example (displaying directories on a form), you can use async / await (if .NET 4.5 is available), which simplifies the code (and automatically synchronizes the thread from which you need to access the UI):
public partial class Form1 : Form { public Form1() { InitializeComponent(); } private async void EnumerateDirsButton_Click(object sender, EventArgs e) { await EnumerateDirs("c:\\"); } private async Task EnumerateDirs(string path) { try { var dirs = Directory.EnumerateDirectories(path); foreach (var dir in dirs) { DirsListBox.Items.Add(dir); await EnumerateDirs(dir); await Task.Delay(1); } } catch (Exception exception) { // handle exception } } } Task.Delay(1) added so that the list has time to redraw.