private static T ReduceTask <T>(int start, int end, int grainSize, ReduceDelegate <T> loopbody, CombineDelegate <T> combineMethod) { int num = end - start; T result; if (num > grainSize) { int middle = (num / 2) + start; Future <T> task = new DelegateFuture <T>(delegate { return(ReduceTask(start, middle, grainSize, loopbody, combineMethod)); }).Start(); result = ReduceTask(middle, end, grainSize, loopbody, combineMethod); return(combineMethod(result, task.Result())); } // grainSize is never less than 1, thus num cannot be less than one. if (num == 1) { return(loopbody(start)); } result = combineMethod(loopbody(start), loopbody(start + 1)); for (int i = start + 2; i < end; i++) { result = combineMethod(result, loopbody(i)); } return(result); }
/// <summary> /// Evaluates a list of kernels against a byte[,] image. /// </summary> /// <param name="operand">The image to parse.</param> /// <param name="kernels">The kernels to apply.</param> /// <param name="evaluateKernel">The "map" function to use. For further explaination, /// refer to the documentation of Kernel2DBatch.</param> /// <param name="reduce">The "reduce" function to use. For further explaination, /// refer to the documentation of Kernel2DBatch.</param> /// <returns>The transformed byte[,].</returns> public static byte[,] Evaluate( byte[,] operand, Kernel2D[] kernels, EvaluateKernelDelegate evaluateKernel, ReduceDelegate reduce) { int width = operand.GetLength(0); int height = operand.GetLength(1); byte[,] ret = new byte[width, height]; List<double> evaluations = new List<double>(); for (int x = 0; x < width; ++x) { for (int y = 0; y < height; ++y) { evaluations.Clear(); // -> Map for (int i = 0; i < kernels.Length; ++i) { // Evaluate evaluations.Add(evaluateKernel(kernels[i], operand, x, y)); } // -> Reduce ret[x, y] = reduce(evaluations); } } return ret; }
/// <summary> /// Defines the View's <see cref="Couchbase.Lite.MapDelegate"/> /// and <see cref="Couchbase.Lite.ReduceDelegate"/>. /// </summary> /// <remarks> /// Defines a view's functions. /// The view's definition is given as a class that conforms to the Mapper or /// Reducer interface (or null to delete the view). The body of the block /// should call the 'emit' object (passed in as a paramter) for every key/value pair /// it wants to write to the view. /// Since the function itself is obviously not stored in the database (only a unique /// string idenfitying it), you must re-define the view on every launch of the app! /// If the database needs to rebuild the view but the function hasn't been defined yet, /// it will fail and the view will be empty, causing weird problems later on. /// It is very important that this block be a law-abiding map function! As in other /// languages, it must be a "pure" function, with no side effects, that always emits /// the same values given the same input document. That means that it should not access /// or change any external state; be careful, since callbacks make that so easy that you /// might do it inadvertently! The callback may be called on any thread, or on /// multiple threads simultaneously. This won't be a problem if the code is "pure" as /// described above, since it will as a consequence also be thread-safe. /// </remarks> /// <returns> /// <c>true</c> if the <see cref="Couchbase.Lite.MapDelegate"/> /// and <see cref="Couchbase.Lite.ReduceDelegate"/> were set, otherwise <c>false</c>. /// If the values provided are identical to the values that are already set, /// then the values will not be updated and <c>false</c> will be returned. /// In addition, if <c>true</c> is returned, the index was deleted and /// will be rebuilt on the next <see cref="Couchbase.Lite.Query"/> execution. /// </returns> /// <param name="map">The <see cref="Couchbase.Lite.MapDelegate"/> to set.</param> /// <param name="reduce">The <see cref="Couchbase.Lite.ReduceDelegate"/> to set.</param> /// <param name="version"> /// The key of the property value to return. The value of this parameter must change /// when the <see cref="Couchbase.Lite.MapDelegate"/> and/or <see cref="Couchbase.Lite.ReduceDelegate"/> /// are changed in a way that will cause them to produce different results. /// </param> public Boolean SetMapReduce(MapDelegate map, ReduceDelegate reduce, String version) { System.Diagnostics.Debug.Assert(map != null); System.Diagnostics.Debug.Assert(version != null); // String.Empty is valid. Map = map; Reduce = reduce; if (!Database.Open()) { return(false); } // Update the version column in the database. This is a little weird looking // because we want to // avoid modifying the database if the version didn't change, and because the // row might not exist yet. var storageEngine = this.Database.StorageEngine; // Older Android doesnt have reliable insert or ignore, will to 2 step // FIXME review need for change to execSQL, manual call to changes() var sql = "SELECT name, version FROM views WHERE name=?"; // TODO: Convert to ADO params. var args = new [] { Name }; Cursor cursor = null; try { cursor = storageEngine.RawQuery(sql, args); if (!cursor.MoveToNext()) { // no such record, so insert var insertValues = new ContentValues(); insertValues["name"] = Name; insertValues["version"] = version; storageEngine.Insert("views", null, insertValues); return(true); } var updateValues = new ContentValues(); updateValues["version"] = version; updateValues["lastSequence"] = 0; var whereArgs = new [] { Name, version }; var rowsAffected = storageEngine.Update("views", updateValues, "name=? AND version!=?", whereArgs); return(rowsAffected > 0); } catch (SQLException e) { Log.E(Database.Tag, "Error setting map block", e); return(false); } finally { if (cursor != null) { cursor.Close(); } } }
private static object CallReduce(ReduceDelegate reduce, IList <object> keys, IList <object> vals) { if (reduce == null) { return(null); } #if PARSED_KEYS var lazyKeys = keys; #else var lazyKeys = new LazyJsonArray(keys); #endif var lazyValues = new LazyJsonArray(vals); try { var result = reduce(lazyKeys, lazyValues, false); if (result != null) { return(result); } } catch (Exception e) { Log.To.Query.W(Tag, "Exception in reduce block, returning null", e); } return(null); }
//*** JavaScript View ***// private Couchbase.Lite.View CompileView(Database db, string viewName, JObject viewProps) { JToken language; if (!viewProps.TryGetValue("language", out language)) { language = "javascript"; } JToken mapSource; if (!viewProps.TryGetValue("map", out mapSource)) { return(null); } IViewCompiler viewCompiler = Couchbase.Lite.View.Compiler; IViewCompiler test = new JSViewCompilerCopy(); Couchbase.Lite.View.Compiler = test; MapDelegate mapBlock = Couchbase.Lite.View.Compiler.CompileMap(mapSource.Value <string>(), language.Value <string>()); if (mapBlock == null) { return(null); } string mapID = db.Name + ":" + viewName + ":" + mapSource.Value <string>().GetHashCode(); JToken reduceSource = null; ReduceDelegate reduceBlock = null; if (viewProps.TryGetValue("reduce", out reduceSource)) { // Couchbase.Lite.View.compiler est null et Couchbase.Lite.Listener.JSViewCompiler est inaccessible (même avec la reflection) reduceBlock = Couchbase.Lite.View.Compiler.CompileReduce(reduceSource.Value <string>(), language.Value <string>()); if (reduceBlock == null) { return(null); } mapID += ":" + reduceSource.Value <string>().GetHashCode(); } Couchbase.Lite.View view = db.GetView(viewName); view.SetMapReduce(mapBlock, reduceBlock, mapID); JToken collation = null; if (viewProps.TryGetValue("collation", out collation)) { if ("raw".Equals((String)collation)) { // ??? } } return(view); }
public unsafe C4ManagedReduceFunction(ManagedAccumulateDelegate accumulate, ManagedReduceDelegate reduce, object context) { _accumulate = accumulate; _reduce = reduce; _context = context; _unmanaged[0] = new AccumulateDelegate(Accumulate); _unmanaged[1] = new ReduceDelegate(Reduce); Native = new C4ReduceFunction(_unmanaged[0] as AccumulateDelegate, _unmanaged[1] as ReduceDelegate, null); }
/// <summary> /// Reduces the specified collection to a singular value according to the specified reduce function. /// </summary> /// <typeparam name="TItem">The type of items in the target collection.</typeparam> /// <typeparam name="TMemo">The type of the singular value to reduce the collection to.</typeparam> /// <param name="target">The collection to operate on.</param> /// <param name="initial">The initial value for the reduce operation.</param> /// <param name="reduceFunction">A delegate that performs the reduce operation.</param> /// <returns>The value of the reduce operation.</returns> public static TMemo Reduce <TItem, TMemo>(IEnumerable target, TMemo initial, ReduceDelegate <TItem, TMemo> reduceFunction) { TMemo memo = initial; foreach (TItem item in target) { memo = reduceFunction(item, memo); } return(memo); }
//For JSViewCompiler internal static ReduceDelegate Get(string name) { ReduceDelegate retVal = null; if (!MAP.TryGetValue(name, out retVal)) { return(null); } return(retVal); }
internal Status Compile(IDictionary <string, object> viewProps, string language) { language = language ?? "javascript"; string mapSource = viewProps.Get("map") as string; if (mapSource == null) { return(new Status(StatusCode.NotFound)); } MapDelegate mapDelegate = Compiler.CompileMap(mapSource, language); if (mapDelegate == null) { Log.To.View.W(TAG, "{0} could not compile {1} map fn: {2}", Name, language, new SecureLogString(mapSource, LogMessageSensitivity.PotentiallyInsecure)); return(new Status(StatusCode.CallbackError)); } string reduceSource = viewProps.Get("reduce") as string; ReduceDelegate reduceDelegate = null; if (reduceSource != null) { reduceDelegate = Compiler.CompileReduce(reduceSource, language); if (reduceDelegate == null) { Log.To.View.W(TAG, "{0} could not compile {1} reduce fn: {2}", Name, language, new SecureLogString(reduceSource, LogMessageSensitivity.PotentiallyInsecure)); return(new Status(StatusCode.CallbackError)); } } string version = Misc.HexSHA1Digest(Manager.GetObjectMapper().WriteValueAsBytes(viewProps)); SetMapReduce(mapDelegate, reduceDelegate, version); DocumentType = viewProps.GetCast <string>("documentType"); var options = viewProps.Get("options").AsDictionary <string, object>(); Collation = ViewCollation.Unicode; if (options != null && options.ContainsKey("collation")) { string collation = options["collation"] as string; if (collation.ToLower().Equals("raw")) { Collation = ViewCollation.Raw; } } return(new Status(StatusCode.Ok)); }
private static object CallReduce(ReduceDelegate reduce, List <object> keysToReduce, List <object> valuesToReduce) { if (reduce == null) { return(null); } try { object result = reduce(keysToReduce, valuesToReduce, false); if (result != null) { return(result); } } catch (Exception e) { Log.E(TAG, "Exception in reduce block", e); } return(null); }
private QueryRow CreateReducedRow(object key, bool group, int groupLevel, ReduceDelegate reduce, Func <QueryRow, bool> filter, IList <object> keysToReduce, IList <object> valsToReduce) { try { var row = new QueryRow(null, 0, group ? GroupKey(key, groupLevel) : null, CallReduce(reduce, keysToReduce, valsToReduce), null, this); if (filter != null && filter(row)) { row = null; } return(row); } catch (CouchbaseLiteException) { Log.To.Query.E(Tag, "Failed to run reduce query for {0}, rethrowing...", Name); throw; } catch (Exception e) { throw Misc.CreateExceptionAndLog(Log.To.Query, e, Tag, "Exception while running reduce query for {0}", Name); } }
private static object CallReduce(ReduceDelegate reduce, List <object> keysToReduce, List <object> valuesToReduce) { if (reduce == null) { return(null); } var lazyKeys = new LazyJsonArray(keysToReduce); var lazyVals = new LazyJsonArray(valuesToReduce); try { object result = reduce(lazyKeys, lazyVals, false); if (result != null) { return(result); } } catch (Exception e) { Log.E(TAG, "Exception in reduce block", e); } return(null); }
private QueryRow CreateReducedRow(object key, bool group, int groupLevel, ReduceDelegate reduce, Func <QueryRow, bool> filter, IList <object> keysToReduce, IList <object> valsToReduce) { try { var row = new QueryRow(null, 0, group ? GroupKey(key, groupLevel) : null, CallReduce(reduce, keysToReduce, valsToReduce), null, this); if (filter != null && filter(row)) { row = null; } return(row); } catch (CouchbaseLiteException) { Log.W(TAG, "Failed to run reduce query for {0}", Name); throw; } catch (Exception e) { throw new CouchbaseLiteException(String.Format("Error running reduce query for {0}", Name), e) { Code = StatusCode.Exception }; } }
/// <summary> /// Defines the View's <see cref="Couchbase.Lite.MapDelegate"/> /// and <see cref="Couchbase.Lite.ReduceDelegate"/>. /// </summary> /// <remarks> /// Defines a view's functions. /// The view's definition is given as a class that conforms to the Mapper or /// Reducer interface (or null to delete the view). The body of the block /// should call the 'emit' object (passed in as a paramter) for every key/value pair /// it wants to write to the view. /// Since the function itself is obviously not stored in the database (only a unique /// string idenfitying it), you must re-define the view on every launch of the app! /// If the database needs to rebuild the view but the function hasn't been defined yet, /// it will fail and the view will be empty, causing weird problems later on. /// It is very important that this block be a law-abiding map function! As in other /// languages, it must be a "pure" function, with no side effects, that always emits /// the same values given the same input document. That means that it should not access /// or change any external state; be careful, since callbacks make that so easy that you /// might do it inadvertently! The callback may be called on any thread, or on /// multiple threads simultaneously. This won't be a problem if the code is "pure" as /// described above, since it will as a consequence also be thread-safe. /// </remarks> /// <returns> /// <c>true</c> if the <see cref="Couchbase.Lite.MapDelegate"/> /// and <see cref="Couchbase.Lite.ReduceDelegate"/> were set, otherwise <c>false</c>. /// If the values provided are identical to the values that are already set, /// then the values will not be updated and <c>false</c> will be returned. /// In addition, if <c>true</c> is returned, the index was deleted and /// will be rebuilt on the next <see cref="Couchbase.Lite.Query"/> execution. /// </returns> /// <param name="map">The <see cref="Couchbase.Lite.MapDelegate"/> to set.</param> /// <param name="reduce">The <see cref="Couchbase.Lite.ReduceDelegate"/> to set.</param> /// <param name="version"> /// The key of the property value to return. The value of this parameter must change /// when the <see cref="Couchbase.Lite.MapDelegate"/> and/or <see cref="Couchbase.Lite.ReduceDelegate"/> /// are changed in a way that will cause them to produce different results. /// </param> public bool SetMapReduce(MapDelegate map, ReduceDelegate reduce, string version) { System.Diagnostics.Debug.Assert(map != null); System.Diagnostics.Debug.Assert(version != null); // String.Empty is valid. var changed = version != MapVersion; var shared = Database.Shared; shared.SetValue("map", Name, Database.Name, map); shared.SetValue("mapVersion", Name, Database.Name, version); shared.SetValue("reduce", Name, Database.Name, reduce); if (changed) { Storage.SetVersion(version); if (_changed != null) { _changed(this, null); } } return(changed); }
void InitializeCouchbaseSummaryView() { var view = Database.GetView("Done"); var mapBlock = new MapDelegate((doc, emit) => { object date; doc.TryGetValue(CreationDatePropertyName, out date); object checkedOff; doc.TryGetValue(CheckboxPropertyName, out checkedOff); if (date != null) { emit(new[] { checkedOff, date }, null); } }); var reduceBlock = new ReduceDelegate((keys, values, rereduce) => { var key = keys.Sum(data => 1 - (int)(((JArray)data)[0]) ); var result = new Dictionary <string, string> { { "Label", "Items Remaining" }, { "Count", key.ToString() } }; return(result); }); view.SetMapReduce(mapBlock, reduceBlock, "1.1"); }
private static object CallReduce(ReduceDelegate reduce, List <object> keysToReduce, List <object> valuesToReduce) { if (reduce == null) { return(null); } var lazyKeys = new LazyJsonArray(keysToReduce); var lazyVals = new LazyJsonArray(valuesToReduce); try { object result = reduce(lazyKeys, lazyVals, false); if (result != null) { return(result); } } catch (Exception e) { Log.To.Query.E(Tag, String.Format("Failed to reduce query (keys={0} vals={1}), returning null...", new SecureLogJsonString(keysToReduce, LogMessageSensitivity.PotentiallyInsecure), new SecureLogJsonString(valuesToReduce, LogMessageSensitivity.PotentiallyInsecure)), e); } return(null); }
public C4ReduceFunction(AccumulateDelegate accumulate, ReduceDelegate reduce, void *context) { this.accumulate = Marshal.GetFunctionPointerForDelegate(accumulate); this.reduce = Marshal.GetFunctionPointerForDelegate(reduce); this.context = context; }
/// <summary>Defines a view's functions.</summary> /// <remarks> /// Defines a view's functions. /// The view's definition is given as a class that conforms to the Mapper or /// Reducer interface (or null to delete the view). The body of the block /// should call the 'emit' object (passed in as a paramter) for every key/value pair /// it wants to write to the view. /// Since the function itself is obviously not stored in the database (only a unique /// string idenfitying it), you must re-define the view on every launch of the app! /// If the database needs to rebuild the view but the function hasn't been defined yet, /// it will fail and the view will be empty, causing weird problems later on. /// It is very important that this block be a law-abiding map function! As in other /// languages, it must be a "pure" function, with no side effects, that always emits /// the same values given the same input document. That means that it should not access /// or change any external state; be careful, since callbacks make that so easy that you /// might do it inadvertently! The callback may be called on any thread, or on /// multiple threads simultaneously. This won't be a problem if the code is "pure" as /// described above, since it will as a consequence also be thread-safe. /// </remarks> public Boolean SetMapReduce(MapDelegate map, ReduceDelegate reduce, String version) { System.Diagnostics.Debug.Assert((map != null)); System.Diagnostics.Debug.Assert(!String.IsNullOrWhiteSpace(version)); Map = map; Reduce = reduce; if (!Database.Open()) { return false; } // Update the version column in the database. This is a little weird looking // because we want to // avoid modifying the database if the version didn't change, and because the // row might not exist yet. var storageEngine = this.Database.StorageEngine; // Older Android doesnt have reliable insert or ignore, will to 2 step // FIXME review need for change to execSQL, manual call to changes() var sql = "SELECT name, version FROM views WHERE name=@"; // TODO: Convert to ADO params. var args = new [] { Name }; Cursor cursor = null; try { cursor = storageEngine.RawQuery(sql, args); if (!cursor.MoveToNext()) { // no such record, so insert var insertValues = new ContentValues(); insertValues["name"] = Name; insertValues["version"] = version; storageEngine.Insert("views", null, insertValues); return true; } var updateValues = new ContentValues(); updateValues["version"] = version; updateValues["lastSequence"] = 0; var whereArgs = new [] { Name, version }; var rowsAffected = storageEngine.Update("views", updateValues, "name=@ AND version!=@", whereArgs); return (rowsAffected > 0); } catch (SQLException e) { Log.E(Database.Tag, "Error setting map block", e); return false; } finally { if (cursor != null) { cursor.Close(); } } }
/// <summary> /// Defines the View's <see cref="Couchbase.Lite.MapDelegate"/> /// and <see cref="Couchbase.Lite.ReduceDelegate"/>. /// </summary> /// <remarks> /// Defines a view's functions. /// The view's definition is given as a class that conforms to the Mapper or /// Reducer interface (or null to delete the view). The body of the block /// should call the 'emit' object (passed in as a paramter) for every key/value pair /// it wants to write to the view. /// Since the function itself is obviously not stored in the database (only a unique /// string idenfitying it), you must re-define the view on every launch of the app! /// If the database needs to rebuild the view but the function hasn't been defined yet, /// it will fail and the view will be empty, causing weird problems later on. /// It is very important that this block be a law-abiding map function! As in other /// languages, it must be a "pure" function, with no side effects, that always emits /// the same values given the same input document. That means that it should not access /// or change any external state; be careful, since callbacks make that so easy that you /// might do it inadvertently! The callback may be called on any thread, or on /// multiple threads simultaneously. This won't be a problem if the code is "pure" as /// described above, since it will as a consequence also be thread-safe. /// </remarks> /// <returns> /// <c>true</c> if the <see cref="Couchbase.Lite.MapDelegate"/> /// and <see cref="Couchbase.Lite.ReduceDelegate"/> were set, otherwise <c>false</c>. /// If the values provided are identical to the values that are already set, /// then the values will not be updated and <c>false</c> will be returned. /// In addition, if <c>true</c> is returned, the index was deleted and /// will be rebuilt on the next <see cref="Couchbase.Lite.Query"/> execution. /// </returns> /// <param name="map">The <see cref="Couchbase.Lite.MapDelegate"/> to set.</param> /// <param name="reduce">The <see cref="Couchbase.Lite.ReduceDelegate"/> to set.</param> /// <param name="version"> /// The key of the property value to return. The value of this parameter must change /// when the <see cref="Couchbase.Lite.MapDelegate"/> and/or <see cref="Couchbase.Lite.ReduceDelegate"/> /// are changed in a way that will cause them to produce different results. /// </param> public bool SetMapReduce(MapDelegate map, ReduceDelegate reduce, string version) { System.Diagnostics.Debug.Assert(map != null); System.Diagnostics.Debug.Assert(version != null); // String.Empty is valid. var changed = version != MapVersion; var shared = Database.Shared; shared.SetValue("map", Name, Database.Name, map); shared.SetValue("mapVersion", Name, Database.Name, version); shared.SetValue("reduce", Name, Database.Name, reduce); if (changed) { Storage.SetVersion(version); if (_changed != null) { _changed(this, null); } } return changed; }
/// <summary> /// Calculates and combines values to a single value. /// </summary> /// <remarks> /// Parallel.Reduce combines multiple associative values into a single value. The ReduceDelegate loopbody /// takes an integer between start and end and returns an element of type T. The CombineDelegate takes two such /// elements and combine them. <p/> /// Parallel.Reduce avoids using locks by dividing the problem into a binary task tree where each task /// updates it's own local value.<p/> /// Grain size is implicit set to two. It's often possible to increase performance by adjusting the grain size. /// To do so use Parallel.Reduce(int start, int end, T initialValue, int grainSize, ReduceDelegate loopbody, CombineDelegate combineMethod). /// Parallel.<p/> /// Reduce catches any uncaught exception raised inside the tasks. Once the exception is caught Parallel.Reduce cancels all /// running tasks that it has started and throws a Jibu.CancelException, containing the original exception. Jibu cancels all /// tasks but it doesn't just brutally stop them - the user defined code must detect and handle the cancellation. For more information on cancellation see Jibu.Task.Cancel and Jibu.CancelException /// </remarks> /// <exception cref="Jibu.CancelException">If one of the Tasks is cancelled, Parallel.Reduce cancels the remaining Tasks /// and throws a Jibu.CancelException.</exception> /// <typeparam name="T">A type that must be associative</typeparam> /// <param name="start">First index, which is incremented by one until it equals end.</param> /// <param name="end">Last index, which is not included in the loop. The loop runs as long as start is less than end.</param> /// <param name="initialValue">The initial value for the result.</param> /// <param name="loopbody">A delegate containing the work. Loopbody is executed once for each iteration.</param> /// <param name="combineMethod">A delegate used to combine the local results</param> /// <returns>A single value of type T</returns> // <example> // - Parallel Reduce Example - // <code><include ReduceExample/ReduceExample.cs></code> // </example> public static T Reduce <T>(int start, int end, T initialValue, ReduceDelegate <T> loopbody, CombineDelegate <T> combineMethod) { return(Reduce(start, end, initialValue, 1, loopbody, combineMethod)); }
void InitializeCouchbaseSummaryView () { var view = Database.GetExistingView("Done") ?? Database.GetView ("Done"); var mapBlock = new MapDelegate ((doc, emit) => { object date; doc.TryGetValue (CreationDatePropertyName, out date); object checkedOff; doc.TryGetValue ("check", out checkedOff); if (date != null) { emit (new[] { checkedOff, date }, null); } }); var reduceBlock = new ReduceDelegate ((keys, values, rereduce) => { var key = keys.Sum(data => 1 - (int)(((JArray)data)[0]) ); var result = new Dictionary<string,string> { {"Label", "Items Remaining"}, {"Count", key.ToString ()} }; return result; }); view.SetMapReduce (mapBlock, reduceBlock, "1.1"); }
/// <summary> /// Calculates and combines values to a single value. /// </summary> /// <remarks> /// Parallel.Reduce combines multiple associative values into a single value. The ReduceDelegate loopbody /// takes an integer between start and end and returns an element of type T. The CombineDelegate takes two such /// elements and combine them. <p/> /// Parallel.Reduce avoids using locks by dividing the problem into a binary task tree where each task /// updates it's own local value.<p/> /// GrainSize specifies a reasonable number of iterations in each task. If the number of iterations is more than grainSize, data /// is split in two and handled separately. /// Adjusting the grain size can lead to better performance, but the optimal grain size depends on the problem at hand. /// Increasing the grain size will decrease the /// amount of tasks, and thus decrease the overhead of setting up tasks. But a small amount of tasks could introduce some load /// balancing problems, if no tasks are available for free processors. Decreasing the grain size will increase the amount of /// tasks and thereby ensure better load balancing, but on the other hand it will also increase the overhead of setting up tasks.<p/> /// Parallel.Reduce catches any uncaught exception raised inside the tasks. Once the exception is caught Parallel.Reduce cancels all /// running tasks that it has started and throws a Jibu.CancelException, containing the original exception. Jibu cancels all /// tasks but it doesn't just brutally stop them - the user defined code must detect and handle the cancellation. For more information on cancellation see Jibu.Task.Cancel and Jibu.CancelException /// </remarks> /// <exception cref="Jibu.CancelException">If one of the Tasks is cancelled, Parallel.Reduce cancels the remaining Tasks /// and throws a Jibu.CancelException.</exception> /// <exception cref="System.ArgumentOutOfRangeException">Is thrown if the grain size is less than 1.</exception> /// <typeparam name="T">A type that must be associative</typeparam> /// <param name="start">First index, which is incremented by one until it equals end.</param> /// <param name="end">Last index, which is not included in the loop. The loop runs as long as start is less than end.</param> /// <param name="initialValue">The initial value for the result.</param> /// <param name="grainSize">A reasonable number of iterations in each task</param> /// <param name="loopbody">A delegate containing the work. Loopbody is executed once for each iteration.</param> /// <param name="combineMethod">A delegate used to combine the local results</param> /// <returns>A single value of type T</returns> // <example> // - Parallel Reduce Example - // <code><include ReduceExample/ReduceExample.cs></code> // </example> public static T Reduce <T>(int start, int end, T initialValue, int grainSize, ReduceDelegate <T> loopbody, CombineDelegate <T> combineMethod) { if (end - start < 1) { return(initialValue); } if (grainSize < 1) { throw new ArgumentOutOfRangeException("Grain size cannot be less than 1."); } return(new DelegateFuture <T>(delegate { return combineMethod(initialValue, ReduceTask <T>(start, end, grainSize, loopbody, combineMethod)); }).Result()); }