在多线程应用程序中的回调函数

huangapple go评论127阅读模式
英文:

a callback in a multithreaded application

问题

以下是您要翻译的代码部分:

  1. 我的应用程序处理目录(每个文件在单独的线程中),并在运行时将信息显示在屏幕上(我使用richtextbox)。
  2. 这是我的代码:
  3. class FilesHandler
  4. {
  5. private List<string> PathesOfFiles = new List<string>();
  6. public void LoadPathes(string pathOfDirectory)
  7. {
  8. string[] allfiles = Directory.GetFiles(pathOfDirectory);
  9. foreach (string filename in allfiles)
  10. {
  11. PathesOfFiles.Add(filename);
  12. }
  13. }
  14. public void HandleEachFile(RichTextBox RTB)
  15. {
  16. foreach (string path in PathesOfFiles)
  17. {
  18. new Thread(() => { CalculateThread(RTB, path); }).Start();
  19. }
  20. }
  21. private void CalculateThread(RichTextBox RTB, string path)
  22. {
  23. Action action2 = () => RTB.Text += DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture) + "\t";
  24. if (RTB.InvokeRequired)
  25. {
  26. RTB.Invoke(action2);
  27. }
  28. else
  29. {
  30. action2();
  31. }
  32. List<string> resultLog = new List<string>();
  33. Stopwatch stopwatch = new Stopwatch();
  34. stopwatch.Start();
  35. resultLog.Add(GetFileName(path) + " {" + string.Join(", ", CountBytes(path)) + " } ");
  36. stopwatch.Stop();
  37. resultLog.Add(stopwatch.ElapsedMilliseconds.ToString() + " ms");
  38. if (RTB.InvokeRequired)
  39. {
  40. RTB.BeginInvoke((MethodInvoker)(() =>
  41. {
  42. RTB.Text += String.Join("", resultLog) + ''\n'';
  43. }
  44. ));
  45. }
  46. else
  47. {
  48. RTB.Text += String.Join("", resultLog) + ''\n'';
  49. }
  50. }
  51. private string GetFileName(string path)
  52. {
  53. return System.IO.Path.GetFileName(path);
  54. }
  55. private ulong[] CountBytes(string filename)
  56. {
  57. ulong[] Bytes = new ulong[256];
  58. byte[] buffer = new byte[4096 * 1000];
  59. int bytesRead = 0;
  60. using (FileStream reader = File.OpenRead(filename))
  61. while ((bytesRead = reader.Read(buffer, 0, buffer.Length)) > 0)
  62. for (int i = 0; i < bytesRead; Bytes[buffer[i++]]++) ;
  63. return Bytes;
  64. }
  65. }

请告诉我如果您需要任何额外的帮助。

英文:

My application processes the directory (each file in a separate thread) and displays information on the screen as it runs (I use richtextbox).

There is my code:

  1. class FilesHandler
  2. {
  3. private List<string> PathesOfFiles = new List<string>();
  4. public void LoadPathes(string pathOfDirectory)
  5. {
  6. string[] allfiles = Directory.GetFiles(pathOfDirectory);
  7. foreach (string filename in allfiles)
  8. {
  9. PathesOfFiles.Add(filename);
  10. }
  11. }
  12. public void HandleEachFile(RichTextBox RTB)
  13. {
  14. foreach (string path in PathesOfFiles)
  15. {
  16. new Thread(() => { CalculateThread(RTB, path); }).Start();
  17. }
  18. }
  19. private void CalculateThread(RichTextBox RTB, string path)
  20. {
  21. Action action2 = () => RTB.Text += DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture) + "\t";
  22. if (RTB.InvokeRequired)
  23. {
  24. RTB.Invoke(action2);
  25. }
  26. else
  27. {
  28. action2();
  29. }
  30. List<string> resultLog = new List<string>();
  31. Stopwatch stopwatch = new Stopwatch();
  32. stopwatch.Start();
  33. resultLog.Add(GetFileName(path) + " {" + string.Join(", ", CountBytes(path)) + " } ");
  34. stopwatch.Stop();
  35. resultLog.Add(stopwatch.ElapsedMilliseconds.ToString() + " ms");
  36. if (RTB.InvokeRequired)
  37. {
  38. RTB.BeginInvoke((MethodInvoker)(() =>
  39. {
  40. RTB.Text += String.Join("", resultLog) + '\n';
  41. }
  42. ));
  43. }
  44. else
  45. {
  46. RTB.Text += String.Join("", resultLog) + '\n';
  47. }
  48. }
  49. private string GetFileName(string path)
  50. {
  51. return System.IO.Path.GetFileName(path);
  52. }
  53. private ulong[] CountBytes(string filename)
  54. {
  55. ulong[] Bytes = new ulong[256];
  56. byte[] buffer = new byte[4096 * 1000];
  57. int bytesRead = 0;
  58. using (FileStream reader = File.OpenRead(filename))
  59. while ((bytesRead = reader.Read(buffer, 0, buffer.Length)) > 0)
  60. for (int i = 0; i < bytesRead; Bytes[buffer[i++]]++) ;
  61. return Bytes;
  62. }
  63. }

I've been doing the output in each thread using Control.Invoke, but my mentor told me to make a callback, but I don't understand how to do it, since I haven't worked with it before.
Thanks!!!

答案1

得分: 0

不必使用 InvokeRequired

而是使用更现代的方法,如 Progress<T> 来返回进度状态给用户界面,和/或使用 await 来将你带回用户界面线程。

CountBytes 交给线程池线程使用 Task.Run,以避免阻塞循环的其余部分。

另外:

  • 使用 EnumerateFiles 替代 GetFiles,并使用 AddRange 替代循环。
  • 使用 List<ulong> 存储接收到的字节数。
  1. class FilesHandler
  2. {
  3. private List<string> PathesOfFiles = new List<string>();
  4. public void LoadPathes(string pathOfDirectory)
  5. {
  6. PathesOfFiles.AddRange(Directory.EnumerateFiles(pathOfDirectory));
  7. }
  8. public void HandleEachFile(IProgress<string> progress)
  9. {
  10. foreach (string path in PathesOfFiles)
  11. {
  12. Task.Run(() => CalculateThread(progress, path));
  13. }
  14. }
  15. private async Task CalculateThread(IProgress<string> progress, string path)
  16. {
  17. progress.Report(DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture) + "\t");
  18. Stopwatch stopwatch = Stopwatch.StartNew();
  19. var bytes = await CountBytes(path);
  20. stopwatch.Stop();
  21. progress.Report(Path.GetFileName(path) + " {" + string.Join(", ", bytes) + " } ");
  22. progress.Report(stopwatch.ElapsedMilliseconds.ToString() + " ms");
  23. }
  24. private async Task<List<ulong>> CountBytes(string filename)
  25. {
  26. List<ulong> allBytesRead = new List<ulong>(256);
  27. byte[] buffer = new byte[4096 * 1000];
  28. int bytesRead = 0;
  29. using (FileStream reader = File.OpenRead(filename))
  30. while ((bytesRead = await reader.ReadAsync(buffer, 0, buffer.Length)) > 0)
  31. for (int i = 0; i < bytesRead; allBytesRead.Add(buffer[i++]));
  32. return allBytesRead;
  33. }
  34. }

现在你可以简单地执行以下操作:

  1. HandleEachFile(new Progress<string>(str => RTB.Text += str));

请注意,显然有更好的方法来获取文件中的所有字节,我假设这是一个练习。

英文:

Don't bother with InvokeRequired.

Instead use more modern methods such as a Progress&lt;T&gt; to return progress status to the UI, and/or await to get you back on to the UI thread.

Hand off CountBytes to a threadpool thread using Task.Run in order not to block the rest of the loop.

Also:

  • Use EnumerateFiles instead of GetFiles, and AddRange instead of looping.
  • Use a List&lt;ulong&gt; for the counts of bytes received.
  1. class FilesHandler
  2. {
  3. private List&lt;string&gt; PathesOfFiles = new List&lt;string&gt;();
  4. public void LoadPathes(string pathOfDirectory)
  5. {
  6. PathesOfFiles.AddRange(Directory.EnumerateFiles(pathOfDirectory))
  7. }
  8. public void HandleEachFile(IProgress&lt;string&gt; progress)
  9. {
  10. foreach (string path in PathesOfFiles)
  11. {
  12. Task.Run(() =&gt; CalculateThread(progress, path));
  13. }
  14. }
  15. private async Task CalculateThread(IProgress&lt;string&gt; progress, string path)
  16. {
  17. progress.Report(DateTime.UtcNow.ToString(&quot;yyyy-MM-dd HH:mm:ss.fff&quot;, CultureInfo.InvariantCulture) + &quot;\t&quot;);
  18. Stopwatch stopwatch = Stopwatch.StartNew();
  19. var bytes = await CountBytes(path);
  20. stopwatch.Stop();
  21. progress.Report((Path.GetFileName(path) + &quot; {&quot; + string.Join(&quot;, &quot;, bytes) + &quot; } &quot;);
  22. progress.Report((stopwatch.ElapsedMilliseconds.ToString() + &quot; ms&quot;);
  23. }
  24. private async Task&lt;List&lt;ulong&gt;&gt; CountBytes(string filename)
  25. {
  26. List&lt;ulong&gt; allBytesRead = new(256);
  27. byte[] buffer = new byte[4096 * 1000];
  28. int bytesRead = 0;
  29. using (FileStream reader = File.OpenRead(filename))
  30. while ((bytesRead = await reader.ReadAsync(buffer, 0, buffer.Length)) &gt; 0)
  31. for (int i = 0; i &lt; bytesRead; allBytesRead.Add(buffer[i++]);
  32. return allBytesRead;
  33. }
  34. }

You can now simply do

  1. HandleEachFile(new Progress&lt;string&gt;(str =&gt; RTB.Text += str);

Note that there are obviously much better ways to get all the bytes in a file, I assume this is for an exercise.

huangapple
  • 本文由 发表于 2023年8月4日 20:56:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/76836126.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定