You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix: allow SaveModel after Complete() in VowpalWabbitThreadedLearning (#4913)
* fix: allow SaveModel/PerformanceStatistics after Complete() in VowpalWabbitThreadedLearning
Previously, calling SaveModel() or accessing PerformanceStatistics after
Complete() threw InvalidOperationException because Complete() immediately
closed the sync action queue. This forced users into a counter-intuitive
pattern of enqueuing saves before signaling completion.
Changes:
- Move CompleteAdding from Complete() into the root completion continuation
using a new atomic CompleteAndRemoveAll(), so sync actions can be enqueued
between the Complete() call and the continuation executing
- Make SaveModel/PerformanceStatistics detect post-completion state and
operate directly on the root VW instance via TryAdd fallback
- Add Flush() method to force AllReduce sync on demand without waiting
for ExampleCountPerRun threshold
Fixes#4911
* fix: replace Task.CompletedTask with Task.FromResult for netstandard2.0
Task.CompletedTask was introduced in .NET 5 and is not available in
netstandard2.0 which is the target framework for vw.parallel.
* docs: clarify async learning model and usage patterns
Improve XML doc comments on VowpalWabbitThreadedLearning to explain:
- Learn() enqueues and returns immediately (async dispatch, not blocking)
- Typical usage flow with code example (learn, complete, save)
- What Complete() guarantees (all examples learned, final allreduce done)
- That SaveModel/PerformanceStatistics work synchronously after Complete
Addresses feedback from #4911 about the TPL completion model being unclear.
/// <param name="line">The example to learn.</param>
357
+
/// <remarks>
358
+
/// This method enqueues the example for asynchronous learning on one of the
359
+
/// internal VW instances and returns immediately. The example string is captured
360
+
/// by the work item and must not be mutated after this call. To ensure all
361
+
/// enqueued learning is complete, call <see cref="Complete"/> or <see cref="Flush"/>.
362
+
/// </remarks>
282
363
publicvoidLearn(stringline)
283
364
{
284
365
Debug.Assert(line!=null);
@@ -287,9 +368,15 @@ public void Learn(string line)
287
368
}
288
369
289
370
/// <summary>
290
-
/// Learns from the given example.
371
+
/// Learns from the given multi-line example.
291
372
/// </summary>
292
373
/// <param name="lines">The multi-line example to learn.</param>
374
+
/// <remarks>
375
+
/// This method enqueues the example for asynchronous learning on one of the
376
+
/// internal VW instances and returns immediately. The lines are captured
377
+
/// by the work item and must not be mutated after this call. To ensure all
378
+
/// enqueued learning is complete, call <see cref="Complete"/> or <see cref="Flush"/>.
379
+
/// </remarks>
293
380
publicvoidLearn(IEnumerable<string>lines)
294
381
{
295
382
Debug.Assert(lines!=null);
@@ -300,69 +387,116 @@ public void Learn(IEnumerable<string> lines)
300
387
/// <summary>
301
388
/// Synchronized performance statistics.
302
389
/// </summary>
303
-
/// <remarks>The task is only completed after synchronization of all instances, triggered <see cref="VowpalWabbitSettings.ExampleCountPerRun"/> example.</remarks>
390
+
/// <remarks>
391
+
/// Can be accessed before or after <see cref="Complete"/>. If accessed after completion,
392
+
/// returns statistics directly from the root VW instance.
0 commit comments