英文:
a callback in a multithreaded application
问题
以下是您要翻译的代码部分:
我的应用程序处理目录(每个文件在单独的线程中),并在运行时将信息显示在屏幕上(我使用richtextbox)。
这是我的代码:
class FilesHandler
{
private List<string> PathesOfFiles = new List<string>();
public void LoadPathes(string pathOfDirectory)
{
string[] allfiles = Directory.GetFiles(pathOfDirectory);
foreach (string filename in allfiles)
{
PathesOfFiles.Add(filename);
}
}
public void HandleEachFile(RichTextBox RTB)
{
foreach (string path in PathesOfFiles)
{
new Thread(() => { CalculateThread(RTB, path); }).Start();
}
}
private void CalculateThread(RichTextBox RTB, string path)
{
Action action2 = () => RTB.Text += DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture) + "\t";
if (RTB.InvokeRequired)
{
RTB.Invoke(action2);
}
else
{
action2();
}
List<string> resultLog = new List<string>();
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
resultLog.Add(GetFileName(path) + " {" + string.Join(", ", CountBytes(path)) + " } ");
stopwatch.Stop();
resultLog.Add(stopwatch.ElapsedMilliseconds.ToString() + " ms");
if (RTB.InvokeRequired)
{
RTB.BeginInvoke((MethodInvoker)(() =>
{
RTB.Text += String.Join("", resultLog) + ''\n'';
}
));
}
else
{
RTB.Text += String.Join("", resultLog) + ''\n'';
}
}
private string GetFileName(string path)
{
return System.IO.Path.GetFileName(path);
}
private ulong[] CountBytes(string filename)
{
ulong[] Bytes = new ulong[256];
byte[] buffer = new byte[4096 * 1000];
int bytesRead = 0;
using (FileStream reader = File.OpenRead(filename))
while ((bytesRead = reader.Read(buffer, 0, buffer.Length)) > 0)
for (int i = 0; i < bytesRead; Bytes[buffer[i++]]++) ;
return Bytes;
}
}
请告诉我如果您需要任何额外的帮助。
英文:
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:
class FilesHandler
{
private List<string> PathesOfFiles = new List<string>();
public void LoadPathes(string pathOfDirectory)
{
string[] allfiles = Directory.GetFiles(pathOfDirectory);
foreach (string filename in allfiles)
{
PathesOfFiles.Add(filename);
}
}
public void HandleEachFile(RichTextBox RTB)
{
foreach (string path in PathesOfFiles)
{
new Thread(() => { CalculateThread(RTB, path); }).Start();
}
}
private void CalculateThread(RichTextBox RTB, string path)
{
Action action2 = () => RTB.Text += DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture) + "\t";
if (RTB.InvokeRequired)
{
RTB.Invoke(action2);
}
else
{
action2();
}
List<string> resultLog = new List<string>();
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
resultLog.Add(GetFileName(path) + " {" + string.Join(", ", CountBytes(path)) + " } ");
stopwatch.Stop();
resultLog.Add(stopwatch.ElapsedMilliseconds.ToString() + " ms");
if (RTB.InvokeRequired)
{
RTB.BeginInvoke((MethodInvoker)(() =>
{
RTB.Text += String.Join("", resultLog) + '\n';
}
));
}
else
{
RTB.Text += String.Join("", resultLog) + '\n';
}
}
private string GetFileName(string path)
{
return System.IO.Path.GetFileName(path);
}
private ulong[] CountBytes(string filename)
{
ulong[] Bytes = new ulong[256];
byte[] buffer = new byte[4096 * 1000];
int bytesRead = 0;
using (FileStream reader = File.OpenRead(filename))
while ((bytesRead = reader.Read(buffer, 0, buffer.Length)) > 0)
for (int i = 0; i < bytesRead; Bytes[buffer[i++]]++) ;
return Bytes;
}
}
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>
存储接收到的字节数。
class FilesHandler
{
private List<string> PathesOfFiles = new List<string>();
public void LoadPathes(string pathOfDirectory)
{
PathesOfFiles.AddRange(Directory.EnumerateFiles(pathOfDirectory));
}
public void HandleEachFile(IProgress<string> progress)
{
foreach (string path in PathesOfFiles)
{
Task.Run(() => CalculateThread(progress, path));
}
}
private async Task CalculateThread(IProgress<string> progress, string path)
{
progress.Report(DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture) + "\t");
Stopwatch stopwatch = Stopwatch.StartNew();
var bytes = await CountBytes(path);
stopwatch.Stop();
progress.Report(Path.GetFileName(path) + " {" + string.Join(", ", bytes) + " } ");
progress.Report(stopwatch.ElapsedMilliseconds.ToString() + " ms");
}
private async Task<List<ulong>> CountBytes(string filename)
{
List<ulong> allBytesRead = new List<ulong>(256);
byte[] buffer = new byte[4096 * 1000];
int bytesRead = 0;
using (FileStream reader = File.OpenRead(filename))
while ((bytesRead = await reader.ReadAsync(buffer, 0, buffer.Length)) > 0)
for (int i = 0; i < bytesRead; allBytesRead.Add(buffer[i++]));
return allBytesRead;
}
}
现在你可以简单地执行以下操作:
HandleEachFile(new Progress<string>(str => RTB.Text += str));
请注意,显然有更好的方法来获取文件中的所有字节,我假设这是一个练习。
英文:
Don't bother with InvokeRequired
.
Instead use more modern methods such as a Progress<T>
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 ofGetFiles
, andAddRange
instead of looping. - Use a
List<ulong>
for the counts of bytes received.
class FilesHandler
{
private List<string> PathesOfFiles = new List<string>();
public void LoadPathes(string pathOfDirectory)
{
PathesOfFiles.AddRange(Directory.EnumerateFiles(pathOfDirectory))
}
public void HandleEachFile(IProgress<string> progress)
{
foreach (string path in PathesOfFiles)
{
Task.Run(() => CalculateThread(progress, path));
}
}
private async Task CalculateThread(IProgress<string> progress, string path)
{
progress.Report(DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture) + "\t");
Stopwatch stopwatch = Stopwatch.StartNew();
var bytes = await CountBytes(path);
stopwatch.Stop();
progress.Report((Path.GetFileName(path) + " {" + string.Join(", ", bytes) + " } ");
progress.Report((stopwatch.ElapsedMilliseconds.ToString() + " ms");
}
private async Task<List<ulong>> CountBytes(string filename)
{
List<ulong> allBytesRead = new(256);
byte[] buffer = new byte[4096 * 1000];
int bytesRead = 0;
using (FileStream reader = File.OpenRead(filename))
while ((bytesRead = await reader.ReadAsync(buffer, 0, buffer.Length)) > 0)
for (int i = 0; i < bytesRead; allBytesRead.Add(buffer[i++]);
return allBytesRead;
}
}
You can now simply do
HandleEachFile(new Progress<string>(str => 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论