没有令牌的F#异步任务取消

时间:2016-02-15 23:08:11

标签: multithreading asynchronous f# task

我正在尝试解析数百个C源文件,将数十个软件信号变量映射到物理硬件引脚的名称。我试图在F#

中异步执行此操作
IndirectMappedHWIO
|> Seq.map IndirectMapFromFile  //this is the function with the regex in it
|> Async.Parallel          
|> Async.RunSynchronously  

问题在于我无法弄清楚如何传递CancellationToken来结束我的任务。每个任务都在读取大约300个C文件,因此我希望能够在正则表达式匹配时立即停止任务的执行。我尝试使用Thread.CurrentThread.Abort(),但这似乎不起作用。关于如何为每项任务传递CancellationToken的任何想法?或者根据条件取消任务的任何其他方式?

let IndirectMapFromFile pin = 
async {    
    let innerFunc filename = 
        use streamReader = new StreamReader (filePath + filename)
        while not streamReader.EndOfStream do
            try
                let line1 = streamReader.ReadLine()
                streamReader.ReadLine() |> ignore
                let line2 = streamReader.ReadLine()

                if(obj.ReferenceEquals(line2, null)) then
                    Thread.CurrentThread.Abort()  //DOES NOT WORK!!
                else    
                    let m1 = Regex.Match(line1, @"^.*((Get|Put)\w+).*$");
                    let m2 = Regex.Match(line2, @"\s*return\s*\((\s*" + pin.Name + "\s*)\);");
                    if (m1.Success && m2.Success) then
                        pin.VariableName <- m1.Groups.[1].Value
                        Thread.CurrentThread.Abort() //DOES NOT WORK!!
                    else
                        ()
            with
            | ex -> ()
        ()

    Directory.GetFiles(filePath, "Rte*") //all C source and header files that start with Rte
    |> Array.iter innerFunc
}

1 个答案:

答案 0 :(得分:1)

Asyncs取消指定的操作,例如return!let!do!;他们不只是在任何未知状态下杀死线程,这通常不安全。如果你想让你的asyncs停下来,他们可以举例如:

  • 是递归的,并通过return!进行迭代。调用者将提供CancellationTokenAsync.RunSynchronously并在作业完成时捕获生成的OperationCanceledException

  • 检查一些线程安全状态,并根据它决定停止。

请注意,这些实际上是相同的:迭代数据的工作人员检查发生了什么并以有序的方式取消 。换句话说,很明显他们确切地检查取消。

使用异步取消可能会导致以下内容:

let canceler = new System.Threading.CancellationTokenSource()
let rec worker myParameters =
    async {
        // do stuff
        if amIDone() then canceler.Cancel()
        else return! worker (...) }

let workers = (...) |> Async.Parallel

try Async.RunSynchronously(workers, -1, canceler.Token) |> ignore
with :? System.OperationCanceledException -> ()

停止普通状态可能如下所示:

let keepGoing = ref true
let rec worker myParameters =
    if !keepGoing then
        // do stuff
        if amIDone() then keepGoing := false
        worker (...)

let makeWorker initParams = async { worker initParams }
// make workers
workers |> Async.Parallel |> Async.RunSynchronously |> ignore

如果取消的确切时间是相关的,我相信第二种方法可能不安全,因为在其他线程看到变量变化之前可能会有延迟。这似乎并不重要。