新手级别winforms应用程序中多线程任务的推荐最佳实践

lf5gs5x2  于 2022-11-17  发布在  其他
关注(0)|答案(1)|浏览(127)

我目前正在尝试更新一个非常简单的winforms应用程序,以使用多线程解决方案。但我缺乏如何最好地去做它的背景知识。
我见过很多解决方案都是围绕着后台工作者的列表,或者使用Tasks,或者直接使用Thread,甚至Parallel.ForEach循环。我读得越多,就越不知道什么可能是最好的解决方案。
为了将我的经验应用到实际环境中,我仍然处于编写单线程解决方案的阶段,在我的程序执行繁重任务时,UI无法访问。我足够清楚地知道这并不理想,应该使用backgroundworker之类的工具,但经验不足,还没有实现更好的解决方案。
在本例中,我将姓名和地址数据库加载到内存中,并尝试查找重复项。这两个循环通过相同的地址列表,我认为这是“左循环”和“右循环”。左循环的项目1使用模糊字符串匹配与右循环的每个项目进行比较。任何在容差范围内的内容(且不是同一记录)作为可能的匹配项添加到DataGridView表中。循环“右”循环以尝试查找匹配项,然后对每个“左”循环值重复此操作。
除了它显然可以做得更好。至少它可以是一个后台工作者。但理想的是多个后台工作者。我认为每个“线程”可以循环通过“右”列表的一个“左”列表项。
我有几个要求。

  • 我需要能够传递一个参数给线程(左边的列表数据)。
  • 我需要将潜在匹配添加到UI组件。

可以是单个“左”的“右”列表中的多个匹配
列表项。

  • 能够取消后台线程是很好的,但不是必需的。
  • 如果我有12万个名字和地址,我宁愿不要开始12万个

并发线程。
理想情况下,我更喜欢一个与硬件一起扩展的解决方案(在双核机器上启动50个基本相同的线程似乎违反直觉,硬编码16个相同的后台工作线程似乎很草率)。
最直接的解决方案(对我来说)看起来像是一个后台工作者的列表。除了我不知道如何编写DoWork、RunWorkerCompleted或ProgressedChange函数来科普多个工作者,而不是绑定到一个工作者。
我很欢迎关于我的匹配策略的反馈,但我主要是希望能被指出正确的方向,让这个程序在不到3周的时间内完成,整个时间只使用了我的CPU的6%。特别欢迎具体的实际答案。

xiozqbni

xiozqbni1#

在大多数情况下:
1.BackgroundWorker表示在后台运行并与UI进行一些交互的唯一任务。
1.线程当您有一个必须在后台持续运行的长期任务时。
对你来说,一个背景工作者会很好。

private readonly BackgroundWorker myWk = new BackgroundWorker();

设置员工:

wkNoGen.DoWork += ActionmyWk;
wkNoGen.RunWorkerCompleted += EndmyWk;
wkNoGen.ProgressChanged += ProgressmyWk;
wkNoGen.WorkerReportsProgress = true;
wkNoGen.WorkerSupportsCancellation = true;

启动工作进程:

// for exemple with a list of string : List<string> myStrings
 myWk.RunWorkerAsync(argument: myStrings);

您的员工操作:

private void ActionmyWk (object sender, DoWorkEventArgs e)
{
    // If you have to get an object
    List<string> myStrings = (e.Argument as List<string>);

    // Send update progress
    myWk.ReportProgress(0, $"Worker is starting.");

    // Your work
    foreach (string aString in myStrings)
    {
        // End the worker if cancellation is pending
        if (myWk.CancellationPending) { e.Cancel = true; return; }

        // Do work

    }

}

当您的员工发送更新时执行的操作:

private void ProgressmyWk (object sender, ProgressChangedEventArgs e)
{
    // Use e.UserState to get information from your worker
    var item = e.UserState as string;
    if (item != null)
    {
        Messagebox.Show("Worker update : " + item;
    }
        // Use e.ProgressPercentage if you need to display it
}

工作结束时的操作:

private void EndmyWk (object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Cancelled) { MessageBox.Show("Manual ending."; }
    else { MessageBox.Show("Normal ending."; }
}

如何发送取消:

myWk.CancelAsync();

当你启动你的worker时,你只能发送一个parameter(argument),它可以是你想要的任何东西。所以你可以使用一个struct或者一个objet来包含你所需要的一切。这对于e.UserState也是一样的。

相关问题