Skip to content

Commit 9c681e1

Browse files
authored
Merge pull request #193 from fsprojects/daily-perf-improver/fix-append-memory-leak
Daily Perf Improver: Fix memory leak in append operations (Issue #35)
2 parents 9d27cca + 8366ae5 commit 9c681e1

File tree

1 file changed

+36
-1
lines changed

1 file changed

+36
-1
lines changed

src/FSharp.Control.AsyncSeq/AsyncSeq.fs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,42 @@ module AsyncSeq =
374374
member x.Dispose() = () } }
375375

376376
let append (inp1: AsyncSeq<'T>) (inp2: AsyncSeq<'T>) : AsyncSeq<'T> =
377-
AsyncGenerator.append inp1 inp2
377+
// Optimized append implementation that doesn't create generator chains
378+
// This fixes the memory leak issue in Issue #35
379+
{ new IAsyncEnumerable<'T> with
380+
member x.GetEnumerator() =
381+
let mutable currentEnumerator : IAsyncEnumerator<'T> option = None
382+
let mutable useSecond = false
383+
{ new IAsyncEnumerator<'T> with
384+
member x.MoveNext() = async {
385+
match currentEnumerator with
386+
| None ->
387+
// Start with the first sequence
388+
let enum1 = inp1.GetEnumerator()
389+
currentEnumerator <- Some enum1
390+
return! x.MoveNext()
391+
| Some enum when not useSecond ->
392+
// Try to get next element from first sequence
393+
let! result = enum.MoveNext()
394+
match result with
395+
| Some v -> return Some v
396+
| None ->
397+
// First sequence is exhausted, switch to second
398+
dispose enum
399+
let enum2 = inp2.GetEnumerator()
400+
currentEnumerator <- Some enum2
401+
useSecond <- true
402+
return! x.MoveNext()
403+
| Some enum ->
404+
// Get elements from second sequence
405+
return! enum.MoveNext()
406+
}
407+
member x.Dispose() =
408+
match currentEnumerator with
409+
| Some enum -> dispose enum
410+
| None -> ()
411+
}
412+
}
378413

379414
let inline delay (f: unit -> AsyncSeq<'T>) : AsyncSeq<'T> =
380415
AsyncGenerator.delay f

0 commit comments

Comments
 (0)