设计:任务异步模式(带等待/异步的TAP),与带信令的线程相比,与其他线程结构相比

本文关键字:异步 线程 信令 任务 线程结构 其他 模式 等待 设计 TAP | 更新日期: 2023-09-27 18:26:15

如果能为重新设计以下C#程序提供帮助,我们将不胜感激。我试图在使用1)TAP实现多线程、2)包含微调器的粗粒度线程(当它们的bool设置为false时终止)或3)使用信号而不是这些bool的相同线程之间进行选择。我将在下面解释程序,以使情况清楚。

程序

该程序是一个C#游戏自动化应用程序,我正在开发它,这是一种更好地学习语言和C#(5.0)功能的有趣方式。它的用户界面需要在应用程序运行时保持响应。

当打开UI中的特定选项卡时,程序会启动一个名为"扫描"的新线程,在另一个类的新方法中,该线程会扫描各种内存位置,并使用UI的SynchronizationContext用这些快速变化的值更新UI中的标签。只要scanning bool为true(通常是程序的整个生命周期),这种情况就会在while(扫描)循环中进行。

当用户单击此选项卡上的"开始"按钮时,程序会启动两个新线程,执行以下操作:线程"运行"将角色沿特定路径移动。线程"Action"点击特定按钮,并在玩家运行路径的同时执行操作。如果出现某种情况,程序应该暂时停止正在运行的线程和操作线程,运行一个方法,当它完成时,返回到正在运行和操作的线程。

当用户单击此选项卡上的"停止"按钮时,自动化将停止,线程将终止。

挑战

我已经创建了一个工作版本,在每个线程中使用连续的微调器循环来处理各种工作。微调器使用while(myBool)运行。对于这三个线程,bool是:扫描、运行和操作。

当我想停止线程时,我将bool设置为false,并使用thread.Join等待线程正常终止,然后再继续。如前所述,线程可以通过用户单击"停止"按钮来停止,也可以作为程序功能的一部分由程序自动停止。在后一种情况下,线程将停止、Joined,然后在稍后阶段重新启动。

在对C#5.0中的线程和新的异步编程工具进行了大量的阅读和研究之后,我意识到我目前的做法可能非常笨拙和不专业。它产生了很多同步/线程安全问题,因为所有这些的目标都是了解更多关于C#的信息,我想让你知道我是否应该将其改为细粒度异步编程方法,酌情将TAP与async和wait一起使用。

这听起来像是一个带有取消令牌的任务可能有用的情况吗?线程在所有长时间运行的操作之后,所以我担心使用线程池(Task.Run)会导致线程池中的卫生状况不佳(过度订阅)。如果异步编程在这里看起来不匹配,那么像我所做的那样使用线程,而是使用信号来启动和停止线程呢?

非常感谢您的任何想法。

设计:任务异步模式(带等待/异步的TAP),与带信令的线程相比,与其他线程结构相比

否。TPL被设计为运行较短的任务,在这些任务中,总是分配新线程会影响性能。它有一些不错的功能,比如作业队列和工作窃取(一个TPL线程可以从另一个线程获取作业)。当然,它可以有更长的运行任务,但你不会从中得到这么多好处。相反,您可以强制TPL分配新线程。

然而,这个问题有点笼统,因为我们需要更多关于您的实际实现的信息,以了解您应该使用什么。对于Scan线程,很明显它应该在单个线程中运行。

但对于其他人来说,这很难知道。他们是一直工作还是定期工作?如果它们一直在工作,你应该把它们放在不同的线程中。

至于线程同步,还有另一种选择。您可以使用ConcurrentQueue来对所有必须绘制的内容进行排队。这样,您就不需要任何同步。只需让UI线程检查队列并在其中绘制任何内容,而生产者可以继续他们的工作。

事实上,通过这种方式,您可以将任何与UI绘图无关的内容移动到其他线程。这也应该提高应用程序的响应能力。

public void ActionRunnerThreadFunc()
{
    _drawQueue.Enqueue(new SpaceShipRenderer(x, y));
}
public void UIThreadFunc()
{
    IItemRender item;
    if (_drawQueue.TryDequeue(out item))
        item.Draw(drawContext);
}