diff --git a/LibreMetaverse/AppearanceManager.cs b/LibreMetaverse/AppearanceManager.cs index fe0fe858..e5064764 100644 --- a/LibreMetaverse/AppearanceManager.cs +++ b/LibreMetaverse/AppearanceManager.cs @@ -28,6 +28,7 @@ using System; using System.Collections.Generic; using System.Threading; using System.Linq; +using System.Threading.Tasks; using LibreMetaverse; using Microsoft.Collections.Extensions; using OpenMetaverse.Packets; @@ -405,6 +406,12 @@ namespace OpenMetaverse /// Is server baking complete. It needs doing only once /// private bool ServerBakingDone = false; + + private static readonly ParallelOptions _parallelOptions = new ParallelOptions() + { + MaxDegreeOfParallelism = MAX_CONCURRENT_DOWNLOADS + }; + #endregion Private Members /// @@ -1594,9 +1601,9 @@ namespace OpenMetaverse return true; Logger.DebugLog("Downloading " + pendingWearables + " wearable assets"); - - Parallel.ForEach(Math.Min(pendingWearables, MAX_CONCURRENT_DOWNLOADS), wearables, - delegate(WearableData wearable) + + Parallel.ForEach(wearables, _parallelOptions, + wearable => { if (wearable.Asset != null) return; AutoResetEvent downloadEvent = new AutoResetEvent(false); @@ -1698,14 +1705,14 @@ namespace OpenMetaverse Logger.DebugLog("Downloading " + textureIDs.Count + " textures for baking"); - Parallel.ForEach(MAX_CONCURRENT_DOWNLOADS, textureIDs, - delegate(UUID textureID) + Parallel.ForEach(textureIDs, _parallelOptions, + textureId => { try { AutoResetEvent downloadEvent = new AutoResetEvent(false); - Client.Assets.RequestImage(textureID, + Client.Assets.RequestImage(textureId, delegate(TextureRequestState state, AssetTexture assetTexture) { if (state == TextureRequestState.Finished) @@ -1714,13 +1721,13 @@ namespace OpenMetaverse for (int i = 0; i < Textures.Length; i++) { - if (Textures[i].TextureID == textureID) + if (Textures[i].TextureID == textureId) Textures[i].Texture = assetTexture; } } else { - Logger.Log("Texture " + textureID + " failed to download, one or more bakes will be incomplete", + Logger.Log("Texture " + textureId + " failed to download, one or more bakes will be incomplete", Helpers.LogLevel.Warning); } @@ -1733,7 +1740,7 @@ namespace OpenMetaverse catch (Exception e) { Logger.Log( - $"Download of texture {textureID} failed with exception {e}", + $"Download of texture {textureId} failed with exception {e}", Helpers.LogLevel.Warning, Client); } } @@ -1769,8 +1776,8 @@ namespace OpenMetaverse { DownloadTextures(pendingBakes); - Parallel.ForEach(Math.Min(MAX_CONCURRENT_UPLOADS, pendingBakes.Count), pendingBakes, - delegate(BakeType bakeType) + Parallel.ForEach(pendingBakes, _parallelOptions, + bakeType => { if (!CreateBake(bakeType)) success = false; diff --git a/LibreMetaverse/Parallel.cs b/LibreMetaverse/Parallel.cs deleted file mode 100644 index 3fba1c63..00000000 --- a/LibreMetaverse/Parallel.cs +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright (c) 2006-2016, openmetaverse.co - * All rights reserved. - * - * - Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - Neither the name of the openmetaverse.co nor the names - * of its contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Threading; - -namespace OpenMetaverse -{ - /// - /// Provides helper methods for parallelizing loops - /// - public static class Parallel - { - private static readonly int processorCount = System.Environment.ProcessorCount; - - /// - /// Executes a for loop in which iterations may run in parallel - /// - /// The loop will be started at this index - /// The loop will be terminated before this index is reached - /// Method body to run for each iteration of the loop - public static void For(int fromInclusive, int toExclusive, Action body) - { - For(processorCount, fromInclusive, toExclusive, body); - } - - /// - /// Executes a for loop in which iterations may run in parallel - /// - /// The number of concurrent execution threads to run - /// The loop will be started at this index - /// The loop will be terminated before this index is reached - /// Method body to run for each iteration of the loop - public static void For(int threadCount, int fromInclusive, int toExclusive, Action body) - { - int counter = threadCount; - AutoResetEvent threadFinishEvent = new AutoResetEvent(false); - Exception exception = null; - - --fromInclusive; - - for (int i = 0; i < threadCount; i++) - { - ThreadPool.QueueUserWorkItem( - delegate(object o) - { - int threadIndex = (int)o; - - while (exception == null) - { - int currentIndex = Interlocked.Increment(ref fromInclusive); - - if (currentIndex >= toExclusive) - break; - - try { body(currentIndex); } - catch (Exception ex) { exception = ex; break; } - } - - if (Interlocked.Decrement(ref counter) == 0) - threadFinishEvent.Set(); - }, i - ); - } - - threadFinishEvent.WaitOne(); - - if (exception != null) - throw exception; - } - - /// - /// Executes a foreach loop in which iterations may run in parallel - /// - /// Object type that the collection wraps - /// An enumerable collection to iterate over - /// Method body to run for each object in the collection - public static void ForEach(IEnumerable enumerable, Action body) - { - ForEach(processorCount, enumerable, body); - } - - /// - /// Executes a foreach loop in which iterations may run in parallel - /// - /// Object type that the collection wraps - /// The number of concurrent execution threads to run - /// An enumerable collection to iterate over - /// Method body to run for each object in the collection - public static void ForEach(int threadCount, IEnumerable enumerable, Action body) - { - int counter = threadCount; - AutoResetEvent threadFinishEvent = new AutoResetEvent(false); - IEnumerator enumerator = enumerable.GetEnumerator(); - Exception exception = null; - - for (int i = 0; i < threadCount; i++) - { - ThreadPool.QueueUserWorkItem( - delegate(object o) - { - while (exception == null) - { - T entry; - - lock (enumerator) - { - if (!enumerator.MoveNext()) - break; - entry = enumerator.Current; // Explicit typecast for Mono's sake - } - - try { body(entry); } - catch (Exception ex) { exception = ex; break; } - } - - if (Interlocked.Decrement(ref counter) == 0) - threadFinishEvent.Set(); - }, i - ); - } - - threadFinishEvent.WaitOne(); - - if (exception != null) - throw exception; - } - - /// - /// Executes a series of tasks in parallel - /// - /// A series of method bodies to execute - public static void Invoke(params Action[] actions) - { - Invoke(processorCount, actions); - } - - /// - /// Executes a series of tasks in parallel - /// - /// The number of concurrent execution threads to run - /// A series of method bodies to execute - public static void Invoke(int threadCount, params Action[] actions) - { - int counter = threadCount; - AutoResetEvent threadFinishEvent = new AutoResetEvent(false); - int index = -1; - Exception exception = null; - - for (int i = 0; i < threadCount; i++) - { - ThreadPool.QueueUserWorkItem( - delegate(object o) - { - int threadIndex = (int)o; - - while (exception == null) - { - int currentIndex = Interlocked.Increment(ref index); - - if (currentIndex >= actions.Length) - break; - - try { actions[currentIndex](); } - catch (Exception ex) { exception = ex; break; } - } - - if (Interlocked.Decrement(ref counter) == 0) - threadFinishEvent.Set(); - }, i - ); - } - - threadFinishEvent.WaitOne(); - - if (exception != null) - throw exception; - } - } -}