C# WFA - 将耗时的工作委托给另一个线程

Posted

技术标签:

【中文标题】C# WFA - 将耗时的工作委托给另一个线程【英文标题】:C# WFA - delegate time consuming work to another thread 【发布时间】:2019-01-08 23:02:01 【问题描述】:

我想在 C# (WFA) 中创建一些机制,允许我在运行中向一个特定的单独线程添加一些函数。

public class MyClass

    private Thread specialThread = new Thread();
    MyClass()
    
        regularMethod();
        specialThread.AddNextJob( veryLongTimeConsumingMethod() );
        //....
        anotherUseMethod();
    
    private void veryLongTimeConsumingMethod()
    
        //...time consuming database, logic, etc...
        this.UIThread(delegate ()
        
            control1.Items = updatedItems;
        );
    

    private void anotherUseMethod()
    
        //...another method wants to do a long job
        specialThread.AddNextJob(veryLongTimeConsumingMethod());
    

在所有“工作”完成后,我希望“特殊线程”处于“待机”状态(等待另一个“工作”)。我需要按顺序完成所有“工作”。 有什么通用的方法可以实现吗?

【问题讨论】:

【参考方案1】:

我不久前写过这样的东西。现在你可能会使用 async await 来让东西在后台线程上运行。但这是我写的一个快速任务队列。

public class TaskQueue

    public Queue<Task> CurrentTasks  get; private set; 
    public bool TaskQueueRunning  get; private set; 

    public TaskQueue()
    
        CurrentTasks = new Queue<Task>();
        TaskQueueRunning = false;
    

    public void AddTask(Task task)
    
        CurrentTasks.Enqueue(task);
        ProcessTasks();
    

    private void ProcessTasks()
    
        if (!TaskQueueRunning)
        
            TaskQueueRunning = true;
            ProcessIndividualTask();
        
    

    private void ProcessIndividualTask()
    
        if (CurrentTasks.Count > 0)
        
            TaskItem currenttask = CurrentTasks.Dequeue();
            currenttask.CurrentTask.ContinueWith(x => ProcessIndividualTask());
            currenttask.CurrentTask.Start();
        
        else
        
            TaskQueueRunning = false;
        
    

你在你的主窗体上实例化它:

private TaskQueue backgroundtasks = new TaskQueue();

然后,当您想在后台线程上执行方法时,您将其包装在任务中。例如

Task newtask = new Task(() => MyMethodCall());
backgroundtasks.AddTask(newtask);

或者如果你想内联整个东西:

backgroundtasks.AddTask(new Task(() => MyMethodCall()));

如果任务队列中没有项目,则队列不会运行,如果添加项目,队列将运行。如果您在第一个任务完成时添加多个项目,它将ContinueWith 下一个任务。任务将始终按顺序运行,因为底层类型是队列,只有在当前任务完成后才会运行下一个任务。

这样做的一个限制是您的任务无法返回结果。不过,您可以设置一个任务来写入变量。例如

Task newtask = new Task(() => 
                                  myvar = MyMethodCall();
                              );
backgroundtasks.AddTask(newtask);

这假设您的主窗体上有一个名为 myvar 的属性/变量。但是要小心这一点,因为如果您从不同的任务多次写入同一个变量,您将无法预测任何时候该值是什么 - 特别是如果您从不同的线程访问它。说到跨线程——这里没有防护,所以要特别小心。

建议您研究 Async 和 Await,因为您可能会发现它们更适合您想做的事情。

【讨论】:

投反对票的人愿意评论为什么这个答案被投反对票吗?

以上是关于C# WFA - 将耗时的工作委托给另一个线程的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C# 中按下停止按钮来停止耗时过长的 UI 线程 [关闭]

C# 耗时的程序 界面卡死,如何做一个缓冲界面,例如有个圆圈在旋转的效果展示

C#管理大量耗时的线程,内存占用严重

AsyncContext的startAsync()方法开启异步

为啥我从后台工作人员调用的委托在主线程中运行

C#(094):异步和多线程的区别