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
See examples above. You can the core code and lots of useful extension methods in the `Dasync.Collections` namespace.
4
+
5
+
6
+
__2: Using CancellationToken__
7
+
8
+
```csharp
9
+
usingDasync.Collections;
10
+
11
+
IAsyncEnumerable<int>ProduceNumbers()
12
+
{
13
+
returnnewAsyncEnumerable<int>(asyncyield=> {
14
+
15
+
awaitFooAsync(yield.CancellationToken);
16
+
});
17
+
}
18
+
```
19
+
20
+
__3: Always remember about ConfigureAwait(false)__
21
+
22
+
To avoid performance degradation and possible dead-locks in ASP.NET or WPF applications (or any `SynchronizationContext`-dependent environment), you should always put `ConfigureAwait(false)` in your `await` statements:
The `FirstOrDefaultAsync` method will try to read first value from the `IAsyncEnumerator`, and then will just dispose it. However, disposing `AsyncEnumerator` does not mean that the `queueClient` in the lambda function will be disposed automatically as well, because async methods are just state machines which need somehow to go to a particular state to do the clean-up.
71
+
To provide such behavior, when you dispose an `AsyncEnumerator` before you reach the end of enumeration, it will tell to resume your async lambda function (at `await yield.ReturnAsync()`) with the `AsyncEnumerationCanceledException` (derives from `OperationCanceledException`). Having such exception in your lambda method will break normal flow of enumeration and will go to terminal state of the underlying state machine, what will do the clean-up, i.e. dispose the `queueClient` in this case. You don't need (and shouldn't) catch that exception type, because it's handled internally by `AsyncEnumerator`. The same exception is thrown when you call `yield.Break()`.
72
+
73
+
There is another option to do the cleanup on `Dispose`:
74
+
75
+
```csharp
76
+
usingDasync.Collections;
77
+
78
+
IAsyncEnumerator<int>GetQueueEnumerator()
79
+
{
80
+
varqueueClient=CreateQueueClient();
81
+
82
+
returnnewAsyncEnumerable<int>(asyncyield=>
83
+
{
84
+
while (true)
85
+
{
86
+
varmessage=queueClient.DequeueMessageAsync();
87
+
if (message==null)
88
+
break;
89
+
90
+
awaityield.ReturnAsync(message.Value);
91
+
}
92
+
},
93
+
onDispose: () =>queueClient.Dispose());
94
+
}
95
+
```
96
+
97
+
__5: Why is GetAsyncEnumeratorAsync async?__
98
+
99
+
The `IAsyncEnumerable.GetAsyncEnumeratorAsync()` method is async and returns a `Task<IAsyncEnumerator>`, where the current implementation of `AsyncEnumerable` always runs that method synchronously and just returns an instance of `AsyncEnumerator`. Having interfaces allows you to do your own implementation, where classes mentioned above are just helpers. The initial idea was to be able to support database-like scenarios, where `GetAsyncEnumeratorAsync()` executes a query first (what internally returns a pointer), and the `MoveNextAsync()` enumerates through rows (by using that pointer).
100
+
101
+
__6: Returning IAsyncEnumerable vs IAsyncEnumerator__
102
+
103
+
When you implement a method that returns an async-enumerable collection you have a choice to return either `IAsyncEnumerable` or `IAsyncEnumerator` - the constructors of the helper classes `AsyncEnumerable` and `AsyncEnumerator` are absolutely identical. Both interfaces have same set of useful extension methods, like `ForEachAsync`.
104
+
105
+
When you create an 'enumerable', you create a factory that produces 'enumerators', i.e. you can enumerate through a collection many times. On the other hand, creating an 'enumerator' is needed when you can through a collection only once.
106
+
107
+
__7: Where is Reset or ResetAsync?__
108
+
109
+
The `Reset` method must not be on the `IEnumerator` interface, and should be considered as deprecated. Create a new enumerator instead. This is the reason why the 'oneTimeUse' flag was removed in version 2 of this library.
110
+
111
+
__8: How can I do synchronous for-each enumeration through IAsyncEnumerable?__
112
+
113
+
You can use extension methods like `IAsyncEnumerable.ToEnumerable()` to use built-in `foreach` enumeration, BUT you should never do that! The general idea of this library is to avoid thread-blocking calls on worker threads, where converting an `IAsyncEnumerable` to `IEnumerable` will just defeat the whole purpose of this library. This is the reason why such synchronous extension methods are marked with `[Obsolete]` attribute.
114
+
115
+
__9: What's the difference between ForEachAsync and ParallelForEachAsync?__
116
+
117
+
The `ForEachAsync` allows you to go through a collection and perform an action on every single item in sequential manner. On the other hand, `ParallelForEachAsync` allows you to run the action on multiple items at the same time where the sequential
118
+
order of completion is not guaranteed. For the latter, the degree of the parallelism is controlled by the `maxDegreeOfParalellism`
119
+
argument, however it does not guarantee to spin up the exact amount of threads, because it depends on the [thread pool size](https://msdn.microsoft.com/en-us/library/system.threading.threadpool.setmaxthreads(v=vs.110).aspx) and its occupancy at a moment of time. Such parallel approach is much better than trying to create a task for an action for every single item on the collection and then awaiting on all of them with `Task.WhenAll`, because it adds less overhead to the runtime, better with memory usage, and helps with throttling-sensitive scenarios.
0 commit comments