1- // https://github.com/xamarin/xamarin-android/blob/83854738b8e01747f9536f426fe17ad784cc2081/src/Xamarin.Android.Build.Tasks/Utilities/AsyncTaskExtensions.cs
1+ // https://github.com/xamarin/xamarin-android/blob/83854738b8e01747f9536f426fe17ad784cc2081/src/Xamarin.Android.Build.Tasks/Utilities/AsyncTaskExtensions.cs
22
33using System ;
44using System . Collections . Generic ;
@@ -12,17 +12,24 @@ public static class AsyncTaskExtensions
1212 /// <summary>
1313 /// Creates a collection of Task with proper CancellationToken and error handling and waits via Task.WhenAll
1414 /// </summary>
15- public static Task WhenAll < TSource > ( this AsyncTask asyncTask , IEnumerable < TSource > source , Action < TSource > body )
15+ public static Task WhenAll < TSource > ( this AsyncTask asyncTask , IEnumerable < TSource > source , Action < TSource > body ) =>
16+ asyncTask . WhenAll ( source , body , maxConcurrencyLevel : DefaultMaxConcurrencyLevel ) ;
17+
18+ /// <summary>
19+ /// Creates a collection of Task with proper CancellationToken and error handling and waits via Task.WhenAll
20+ /// </summary>
21+ public static Task WhenAll < TSource > ( this AsyncTask asyncTask , IEnumerable < TSource > source , Action < TSource > body , int maxConcurrencyLevel , TaskCreationOptions creationOptions = TaskCreationOptions . LongRunning )
1622 {
23+ var scheduler = GetTaskScheduler ( maxConcurrencyLevel ) ;
1724 var tasks = new List < Task > ( ) ;
1825 foreach ( var s in source ) {
19- tasks . Add ( Task . Run ( ( ) => {
26+ tasks . Add ( Task . Factory . StartNew ( ( ) => {
2027 try {
2128 body ( s ) ;
2229 } catch ( Exception exc ) {
2330 LogErrorAndCancel ( asyncTask , exc ) ;
2431 }
25- } , asyncTask . CancellationToken ) ) ;
32+ } , asyncTask . CancellationToken , creationOptions , scheduler ) ) ;
2633 }
2734 return Task . WhenAll ( tasks ) ;
2835 }
@@ -31,28 +38,42 @@ public static Task WhenAll<TSource>(this AsyncTask asyncTask, IEnumerable<TSourc
3138 /// Creates a collection of Task with proper CancellationToken and error handling and waits via Task.WhenAll
3239 /// Passes an object the inner method can use for locking. The callback is of the form: (T item, object lockObject)
3340 /// </summary>
34- public static Task WhenAllWithLock < TSource > ( this AsyncTask asyncTask , IEnumerable < TSource > source , Action < TSource , object > body )
41+ public static Task WhenAllWithLock < TSource > ( this AsyncTask asyncTask , IEnumerable < TSource > source , Action < TSource , object > body ) =>
42+ asyncTask . WhenAllWithLock ( source , body , maxConcurrencyLevel : DefaultMaxConcurrencyLevel ) ;
43+
44+ /// <summary>
45+ /// Creates a collection of Task with proper CancellationToken and error handling and waits via Task.WhenAll
46+ /// Passes an object the inner method can use for locking. The callback is of the form: (T item, object lockObject)
47+ /// </summary>
48+ public static Task WhenAllWithLock < TSource > ( this AsyncTask asyncTask , IEnumerable < TSource > source , Action < TSource , object > body , int maxConcurrencyLevel , TaskCreationOptions creationOptions = TaskCreationOptions . LongRunning )
3549 {
50+ var scheduler = GetTaskScheduler ( maxConcurrencyLevel ) ;
3651 var lockObject = new object ( ) ;
3752 var tasks = new List < Task > ( ) ;
3853 foreach ( var s in source ) {
39- tasks . Add ( Task . Run ( ( ) => {
54+ tasks . Add ( Task . Factory . StartNew ( ( ) => {
4055 try {
4156 body ( s , lockObject ) ;
4257 } catch ( Exception exc ) {
4358 LogErrorAndCancel ( asyncTask , exc ) ;
4459 }
45- } , asyncTask . CancellationToken ) ) ;
60+ } , asyncTask . CancellationToken , creationOptions , scheduler ) ) ;
4661 }
4762 return Task . WhenAll ( tasks ) ;
4863 }
4964
5065 /// <summary>
5166 /// Calls Parallel.ForEach() with appropriate ParallelOptions and exception handling.
5267 /// </summary>
53- public static ParallelLoopResult ParallelForEach < TSource > ( this AsyncTask asyncTask , IEnumerable < TSource > source , Action < TSource > body )
68+ public static ParallelLoopResult ParallelForEach < TSource > ( this AsyncTask asyncTask , IEnumerable < TSource > source , Action < TSource > body ) =>
69+ asyncTask . ParallelForEach ( source , body , maxConcurrencyLevel : DefaultMaxConcurrencyLevel ) ;
70+
71+ /// <summary>
72+ /// Calls Parallel.ForEach() with appropriate ParallelOptions and exception handling.
73+ /// </summary>
74+ public static ParallelLoopResult ParallelForEach < TSource > ( this AsyncTask asyncTask , IEnumerable < TSource > source , Action < TSource > body , int maxConcurrencyLevel )
5475 {
55- var options = ParallelOptions ( asyncTask ) ;
76+ var options = ParallelOptions ( asyncTask , maxConcurrencyLevel ) ;
5677 return Parallel . ForEach ( source , options , s => {
5778 try {
5879 body ( s ) ;
@@ -66,9 +87,16 @@ public static ParallelLoopResult ParallelForEach<TSource> (this AsyncTask asyncT
6687 /// Calls Parallel.ForEach() with appropriate ParallelOptions and exception handling.
6788 /// Passes an object the inner method can use for locking. The callback is of the form: (T item, object lockObject)
6889 /// </summary>
69- public static ParallelLoopResult ParallelForEachWithLock < TSource > ( this AsyncTask asyncTask , IEnumerable < TSource > source , Action < TSource , object > body )
90+ public static ParallelLoopResult ParallelForEachWithLock < TSource > ( this AsyncTask asyncTask , IEnumerable < TSource > source , Action < TSource , object > body ) =>
91+ asyncTask . ParallelForEachWithLock ( source , body , maxConcurrencyLevel : DefaultMaxConcurrencyLevel ) ;
92+
93+ /// <summary>
94+ /// Calls Parallel.ForEach() with appropriate ParallelOptions and exception handling.
95+ /// Passes an object the inner method can use for locking. The callback is of the form: (T item, object lockObject)
96+ /// </summary>
97+ public static ParallelLoopResult ParallelForEachWithLock < TSource > ( this AsyncTask asyncTask , IEnumerable < TSource > source , Action < TSource , object > body , int maxConcurrencyLevel )
7098 {
71- var options = ParallelOptions ( asyncTask ) ;
99+ var options = ParallelOptions ( asyncTask , maxConcurrencyLevel ) ;
72100 var lockObject = new object ( ) ;
73101 return Parallel . ForEach ( source , options , s => {
74102 try {
@@ -79,28 +107,47 @@ public static ParallelLoopResult ParallelForEachWithLock<TSource> (this AsyncTas
79107 } ) ;
80108 }
81109
82- static ParallelOptions ParallelOptions ( AsyncTask asyncTask ) => new ParallelOptions {
110+ static ParallelOptions ParallelOptions ( AsyncTask asyncTask , int maxConcurrencyLevel ) => new ParallelOptions {
83111 CancellationToken = asyncTask . CancellationToken ,
84- TaskScheduler = TaskScheduler . Default ,
112+ TaskScheduler = GetTaskScheduler ( maxConcurrencyLevel ) ,
85113 } ;
86114
115+ static TaskScheduler GetTaskScheduler ( int maxConcurrencyLevel )
116+ {
117+ var pair = new ConcurrentExclusiveSchedulerPair ( TaskScheduler . Default , maxConcurrencyLevel ) ;
118+ return pair . ConcurrentScheduler ;
119+ }
120+
121+ static int DefaultMaxConcurrencyLevel => Math . Max ( 1 , Environment . ProcessorCount - 1 ) ;
122+
87123 static void LogErrorAndCancel ( AsyncTask asyncTask , Exception exc )
88124 {
89125 asyncTask . LogCodedError ( "XA0000" , Properties . Resources . XA0000_Exception , exc ) ;
90126 asyncTask . Cancel ( ) ;
91127 }
92128
93129 /// <summary>
94- /// Calls Task.Run() with a proper CancellationToken.
130+ /// Calls Task.Factory.StartNew() with a proper CancellationToken, TaskScheduler, and TaskCreationOptions.LongRunning.
131+ /// </summary>
132+ public static Task RunTask ( this AsyncTask asyncTask , Action body ) =>
133+ asyncTask . RunTask ( body , maxConcurrencyLevel : DefaultMaxConcurrencyLevel ) ;
134+
135+ /// <summary>
136+ /// Calls Task.Factory.StartNew() with a proper CancellationToken
95137 /// </summary>
96- public static Task RunTask ( this AsyncTask asyncTask , Action body ) =>
97- Task . Run ( body , asyncTask . CancellationToken ) ;
138+ public static Task RunTask ( this AsyncTask asyncTask , Action body , int maxConcurrencyLevel , TaskCreationOptions creationOptions = TaskCreationOptions . LongRunning ) =>
139+ Task . Factory . StartNew ( body , asyncTask . CancellationToken , creationOptions , GetTaskScheduler ( maxConcurrencyLevel ) ) ;
98140
141+ /// <summary>
142+ /// Calls Task.Factory.StartNew<T>() with a proper CancellationToken, TaskScheduler, and TaskCreationOptions.LongRunning.
143+ /// </summary>
144+ public static Task < TSource > RunTask < TSource > ( this AsyncTask asyncTask , Func < TSource > body ) =>
145+ asyncTask . RunTask ( body , maxConcurrencyLevel : DefaultMaxConcurrencyLevel ) ;
99146
100147 /// <summary>
101- /// Calls Task.Run <T>() with a proper CancellationToken.
148+ /// Calls Task.Factory.StartNew <T>() with a proper CancellationToken.
102149 /// </summary>
103- public static Task < TSource > RunTask < TSource > ( this AsyncTask asyncTask , Func < TSource > body ) =>
104- Task . Run ( body , asyncTask . CancellationToken ) ;
150+ public static Task < TSource > RunTask < TSource > ( this AsyncTask asyncTask , Func < TSource > body , int maxConcurrencyLevel , TaskCreationOptions creationOptions = TaskCreationOptions . LongRunning ) =>
151+ Task . Factory . StartNew ( body , asyncTask . CancellationToken , creationOptions , GetTaskScheduler ( maxConcurrencyLevel ) ) ;
105152 }
106153}
0 commit comments