[英]Can you use Thread.CurrentPrincipal with F# async workflows?
有沒有人在F#異步代碼中使用設置Thread.CurrentPrincipal
進行身份驗證?
是否有任何陷阱需要注意,或者只是按預期工作?
這聽起來不是一個好主意,因為Thread.CurrentPrincipal
依賴於與給定線程關聯的IPrincipal
,但在異步工作流中,您可能不會一直在同一個線程上運行。
考慮這個例子:
open System.Threading
let collectThreadInformation jobId =
async {
let tId1 = Thread.CurrentThread.ManagedThreadId
do! Async.Sleep 1000
let tId2 = Thread.CurrentThread.ManagedThreadId
return jobId, tId1, tId2 }
這是一個簡單的異步工作流,可以在睡眠之前和之后報告線程ID一秒鍾。 以下是並行運行其中10個的看法:
> [1 .. 10]
|> List.map collectThreadInformation
|> Async.Parallel
|> Async.RunSynchronously;;
val it : (int * int * int) [] =
[|(1, 15, 15); (2, 14, 15); (3, 15, 15); (4, 15, 15); (5, 15, 15);
(6, 15, 15); (7, 15, 15); (8, 14, 15); (9, 15, 15); (10, 15, 15)|]
如您所見,一些線程ID在Sleep
之前和之后發生了變化,例如第二個元組: (2, 14, 15)
2,14,15 (2, 14, 15)
。 在Sleep
之前,它在線程14上運行,但在睡眠之后,它在線程15上復活。
我認為將IPrincipal
實例作為函數參數傳遞會更安全。
我在不同的地方對此有各種相互矛盾的反應,所以我實際上構建了一個測試程序。 運行下面的代碼表明,當async
工作流在ThreadPool上運行時,它們確實保留了線程上下文。
module TestCurrentPrinciple
open System
open System.Security.Principal
open System.Threading
let rand = Random()
let spawnWorkflow userName =
async {
let identity = GenericIdentity(userName)
let principle = GenericPrincipal(identity, [||])
Thread.CurrentPrincipal <- principle
for i in 1..10000 do
let principleName = Thread.CurrentPrincipal.Identity.Name
if principleName <> userName then
failwithf "Mismatch! Principle name %s does not match username %s (Iteration %d)"
principleName userName i
do! Async.Sleep(rand.Next(10))
}
let names =
[ "mavnn"; "ploeh"; "dsyme"; "biboudis"; "MattDrivenDev"; "fssnip"; "marprz_93"; "skillsmatter"; "thinkb4coding" ]
printfn "Starting"
names
|> List.map spawnWorkflow
|> Async.Parallel
|> Async.RunSynchronously
|> ignore
printfn "Done"
Console.ReadLine() |> ignore
這對我目前的項目可能很有意思。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.