如何从按钮单击事件中取消与其他进程并行运行的单个异步计算

如何解决如何从按钮单击事件中取消与其他进程并行运行的单个异步计算

|| 我已经准备了以下WinForms代码,以使其尽可能简单,以帮助回答我的问题。您可以看到我有一个开始按钮,该按钮可以并行设置和运行3个不同的异步计算,每个计算都会做一些工作,然后用结果更新标签。我有3个取消按钮,分别与每个异步计算并行运行。如何连接这些取消按钮以取消其相应的异步计算,同时允许其他按钮继续并行运行?谢谢!
open System.Windows.Forms

type MyForm() as this =
    inherit Form()
    let lbl1 = new Label(AutoSize=true,Text=\"Press Start\")
    let lbl2 = new Label(AutoSize=true,Text=\"Press Start\")
    let lbl3 = new Label(AutoSize=true,Text=\"Press Start\")

    let cancelBtn1 = new Button(AutoSize=true,Enabled=false,Text=\"Cancel\")
    let cancelBtn2 = new Button(AutoSize=true,Text=\"Cancel\")
    let cancelBtn3 = new Button(AutoSize=true,Text=\"Cancel\")

    let startBtn = new Button(AutoSize=true,Text=\"Start\")

    let panel = new FlowLayoutPanel(AutoSize=true,Dock=DockStyle.Fill,FlowDirection=FlowDirection.TopDown)
    do
        panel.Controls.AddRange [|startBtn; lbl1; cancelBtn1; lbl2; cancelBtn2; lbl3; cancelBtn3; |]
        this.Controls.Add(panel)

        startBtn.Click.Add <| fun _ ->
            startBtn.Enabled <- false
            [lbl1;lbl2;lbl3] |> List.iter (fun lbl -> lbl.Text <- \"Loading...\")
            [cancelBtn1;cancelBtn2;cancelBtn3] |> List.iter (fun cancelBtn -> cancelBtn.Enabled <- true)

            let guiContext = System.Threading.SynchronizationContext.Current

            let work (timeout:int) = //work is not aware it is being run within an async computation
                System.Threading.Thread.Sleep(timeout)
                System.DateTime.Now.Ticks |> string

            let asyncUpdate (lbl:Label) (cancelBtn:Button) timeout =
                async {
                    let result = work timeout //\"cancelling\" means forcibly aborting,since work may be stuck in an infinite loop
                    do! Async.SwitchToContext guiContext
                    cancelBtn.Enabled <- false
                    lbl.Text <- result
                }

            let parallelAsyncUpdates =
                [|asyncUpdate lbl1 cancelBtn1 3000; asyncUpdate lbl2 cancelBtn2 6000; asyncUpdate lbl3 cancelBtn3 9000;|]
                |> Async.Parallel
                |> Async.Ignore

            Async.StartWithContinuations(
                parallelAsyncUpdates,(fun _ -> startBtn.Enabled <- true),(fun _ -> ()),(fun _ -> ()))
    

解决方法

通常,不合作地取消线程是一个坏习惯,因此,我不建议您这样做。例如,请参阅本文。当您直接使用
Thread
进行编程(使用Thread.Abort)时,可以完成此操作,但是.NET的现代并行/异步库(例如TPL或F#Async)都没有使用此功能。如果这确实是您所需要的,那么您将必须显式使用线程。 更好的选择是更改“ 2”功能,以便可以协作取消它。在F#中,这实际上只是意味着将其包装在
async
中并使用
let!
do!
,因为这会自动插入对取消的支持。例如:
let work (timeout:int) = async {
  do! Async.Sleep(timeout)
  return System.DateTime.Now.Ticks |> string }
不使用
async
(例如,如果函数是用C#编写的),则可以传递
CancellationToken
值并将其用于检查是否请求取消(通过调用
ThrowIfCancellationRequestsd
)。然后,您可以使用
Async.Start
开始三个计算(为每个计算创建一个新的
CancellationTokenSource
)。 为了完成某件事,直到它们全部完成,我可能会创建一个简单的代理(触发某个事件,直到它收到指定数量的消息为止)。我认为没有其他更直接的方法(因为
Async.Parallel
在所有工作流程中都使用相同的取消令牌)。 因此,我想这个答案的重点是-如果要取消
work
,那么它应该知道这种情况,以便可以适当地对其进行处理。     ,正如Tomas所说,强行停止线程是一个坏主意,而在我看来,设计一个没有意识到它能够停止的线程会引发标记,但是,如果您要进行长时间的计算,使用某种数据结构(例如2或3D数组),则可以将其设置为
null
,但这违反了F#的许多概念,因为函数所使用的功能不仅应该是不可变的,但是,如果有一些要更改的数组,则别无其他更改。 例如,如果您需要停止正在处理文件的线程(之前我必须这样做),则由于无法删除该文件(已打开),因此可以在记事本中打开它,然后删除所有内容并保存,然后线程崩溃。 因此,您可能想要执行以下操作以实现您的目标,但是,我建议您重新评估设计,看看是否有更好的方法可以做到这一点。     

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?