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

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

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&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.
class FilesHandler
{
    private List&lt;string&gt; PathesOfFiles = new List&lt;string&gt;();

    public void LoadPathes(string pathOfDirectory)
    {
        PathesOfFiles.AddRange(Directory.EnumerateFiles(pathOfDirectory))
    }

    public void HandleEachFile(IProgress&lt;string&gt; progress)
    {
        foreach (string path in PathesOfFiles)
        {
            Task.Run(() =&gt; CalculateThread(progress, path));
        }
    }

    private async Task CalculateThread(IProgress&lt;string&gt; progress, string path)
    {
       progress.Report(DateTime.UtcNow.ToString(&quot;yyyy-MM-dd HH:mm:ss.fff&quot;, CultureInfo.InvariantCulture) + &quot;\t&quot;);

        Stopwatch stopwatch = Stopwatch.StartNew();
        var bytes = await CountBytes(path);
        stopwatch.Stop();

        progress.Report((Path.GetFileName(path) + &quot; {&quot; + string.Join(&quot;, &quot;, bytes) + &quot; } &quot;);
        progress.Report((stopwatch.ElapsedMilliseconds.ToString() + &quot; ms&quot;);
    }

    private async Task&lt;List&lt;ulong&gt;&gt; CountBytes(string filename)
    {
        List&lt;ulong&gt; 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)) &gt; 0)
                for (int i = 0; i &lt; bytesRead; allBytesRead.Add(buffer[i++]);

        return allBytesRead;
    }
}

You can now simply do

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:

确定