簡體   English   中英

沒有令牌的F#異步任務取消

[英]F# Async Task Cancellation without Token

我正在嘗試解析數百個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
}

異步會在指定的操作(例如return!上取消return! let! ,或do! ; 它們不僅會殺死處於未知狀態的線程,這通常是不安全的。 如果您希望異步停止,則可以例如:

  • 遞歸並通過return!進行迭代return! 調用者將向Async.RunSynchronously提供CancellationToken ,並在作業完成時捕獲所產生的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

如果取消的確切時間相關,我相信第二種方法可能並不安全,因為在其他線程看到變量更改之前可能會有所延遲。 這似乎無關緊要。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM