Aşağıdaki sınamayı (F # 2.0 ile oluşturulmuş) çalıştırdığımda OutOfMemoryException olsun. Sistemimde istisna ulaşmak yaklaşık 5 dakika alır (x86 işlemi olarak çalışıyorsa i7-920 6gb ram), ancak her durumda belleğin görev yöneticisinde nasıl büyüdüğünü görebiliriz.Async.StartChild'de bir bellek sızıntısı var mı?
module start_child_test
open System
open System.Diagnostics
open System.Threading
open System.Threading.Tasks
let cnt = ref 0
let sw = Stopwatch.StartNew()
Async.RunSynchronously(async{
while true do
let! x = Async.StartChild(async{
if (Interlocked.Increment(cnt) % 100000) = 0 then
if sw.ElapsedMilliseconds > 0L then
printfn "ops per sec = %d" (100000L*1000L/sw.ElapsedMilliseconds)
else
printfn "ops per sec = INF"
sw.Restart()
GC.Collect()
})
do! x
})
printfn "done...."
Bu kod ile yanlış bir şey görmüyorum, ve büyüyen bellek için herhangi bir neden göremiyorum. herhangi ölçüde bellek tüketimi olmadan iyi çalışır Bu test için
module start_child_fix
open System
open System.Collections
open System.Collections.Generic
open System.Threading
open System.Threading.Tasks
type IAsyncCallbacks<'T> = interface
abstract member OnSuccess: result:'T -> unit
abstract member OnError: error:Exception -> unit
abstract member OnCancel: error:OperationCanceledException -> unit
end
type internal AsyncResult<'T> =
| Succeeded of 'T
| Failed of Exception
| Canceled of OperationCanceledException
type internal AsyncGate<'T> =
| Completed of AsyncResult<'T>
| Subscribed of IAsyncCallbacks<'T>
| Started
| Notified
type Async with
static member StartChildEx (comp:Async<'TRes>) = async{
let! ct = Async.CancellationToken
let gate = ref AsyncGate.Started
let CompleteWith(result:AsyncResult<'T>, callbacks:IAsyncCallbacks<'T>) =
if Interlocked.Exchange(gate, Notified) <> Notified then
match result with
| Succeeded v -> callbacks.OnSuccess(v)
| Failed e -> callbacks.OnError(e)
| Canceled e -> callbacks.OnCancel(e)
let ProcessResults (result:AsyncResult<'TRes>) =
let t = Interlocked.CompareExchange<AsyncGate<'TRes>>(gate, AsyncGate.Completed(result), AsyncGate.Started)
match t with
| Subscribed callbacks ->
CompleteWith(result, callbacks)
| _ ->()
let Subscribe (success, error, cancel) =
let callbacks = {
new IAsyncCallbacks<'TRes> with
member this.OnSuccess v = success v
member this.OnError e = error e
member this.OnCancel e = cancel e
}
let t = Interlocked.CompareExchange<AsyncGate<'TRes>>(gate, AsyncGate.Subscribed(callbacks), AsyncGate.Started)
match t with
| AsyncGate.Completed result ->
CompleteWith(result, callbacks)
| _ ->()
Async.StartWithContinuations(
computation = comp,
continuation = (fun v -> ProcessResults(AsyncResult.Succeeded(v))),
exceptionContinuation = (fun e -> ProcessResults(AsyncResult.Failed(e))),
cancellationContinuation = (fun e -> ProcessResults(AsyncResult.Canceled(e))),
cancellationToken = ct
)
return Async.FromContinuations(fun (success, error, cancel) ->
Subscribe(success, error, cancel)
)
}
: Eminim benim argümanlar geçerlidir yapmak için alternatif uygulama yaptı. Ne yazık ki F # 'da fazla tecrübem yok ve bazı şeyleri özlüyorsam şüphelerim var. Hata durumunda, F # takımına nasıl rapor edebilirim?
Bunun neden gerekli olduğunu biliyor musunuz? Neden yeni bir "CTS" oluşturuldu? Sadece orijinal 'ct'yi kullanmak yeterli olmaz mı? – svick
@svick - İyi soru. İç iptal belirtecinin 'StartChild 'için belirtilen zaman aşımını ele almak için kullanıldığını düşünüyorum (bu zaman aşımı, aslında daha sonra sonuç beklemediğiniz sürece' StartChild' denilen hesaplamayı iptal etmemelidir). –
Bunu düşünmedim. Evet, bu mantıklı. – svick