繁体   English   中英

使用任务和并行API进行线程同步

[英]Thread synchronizing using Tasks and Parallel APIs

我粘贴了4个代码段,其中尝试使用以下API进行并行化:

Parallel.ForEach
Parallel.Invoke
Task.Run
Task.Factory.StartNew

问题尝试并行化,以使有两个for循环,内部循环和外部循环,并且每次执行外部循环时,内部循环中的所有内容都应在并行中执行。

我可以使用Parallel.ForEach使其工作,其他所有原因都会导致内部计数器异常,该值超出了数组索引,而我认为情况并非如此。 索引也会比目标高一个值,例如,当索引的大小为500时,它会尝试访问值500,理想情况下它应该在499处停止。我是否错过了什么。 以下是代码段,请看一下:

并行ForEach(工作)

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace TestThreads
{    
    class Elements
    {
        public int innerValue;
        public int outerValue;

        public Elements(int innerValue, int outerValue)
        {
            this.innerValue = innerValue;
            this.outerValue = outerValue;
        }
    }

    class Program
    {
        private static int threadingCounter = 0;
        private static int innerCounter = 500;
        private static int outerCounter = 1000;
        private static int[,] inOut;
        private static int hitCount = 0;
        private static int exceptionCount = 0;
        private static List<int> innerCount = new List<int>();



        static void Main(string[] args)
        {
            inOut = new int[innerCounter, outerCounter];
            Program myProgram = new Program();

            for (int iCount = 0; iCount < innerCounter; iCount++)
                innerCount.Add(iCount);

            try
            {
                for (int outer = 0; outer < outerCounter; outer++)
                {
                    Parallel.ForEach<int>(innerCount, inner =>
                    {
                        myProgram.ThreadCall(new Elements(inner,outer));
                    }
                    );

                    Console.WriteLine("Main Thread Released Post Wait ...");
                    Console.WriteLine("Hit Count :: " + hitCount);
                    Console.WriteLine("Exception Count :: " + exceptionCount);

                    if (threadingCounter != 0)
                        Console.WriteLine("Threading Counter post Inner Loop :: " + threadingCounter);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception :: " + ex.Message);
            }
            finally
            {                
                if (innerCount != null)
                    innerCount = null;

            }
        }


        public void ThreadCall(object state)
        {
            try
            {
                Interlocked.Increment(ref hitCount);

                Elements localElement = (Elements)state;
                int localInner = localElement.innerValue;
                int localOuter = localElement.outerValue;
                int finalValue = inOut[localInner, localOuter];
            }
            catch (Exception ex)
            {               
                Console.WriteLine("Exception :: " + ex.Message);
            }
        }
    }
}

Parallel.Invoke(由于索引值超出数组而失败,尝试获取内部索引-500)

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace TestThreads
{
    /// <summary>
    /// 
    /// </summary>
    class Elements
    {
        public int innerValue;
        public int outerValue;

        public Elements(int innerValue, int outerValue)
        {
            this.innerValue = innerValue;
            this.outerValue = outerValue;
        }
    }

    /// <summary>
    /// 
    /// </summary>
    class Program
    {
        private static int innerCounter = 500;
        private static int outerCounter = 1000;
        private static int[,] inOut;
        private static int hitCount = 0;
        private static int exceptionCount = 0;

        private static List<Action> alSync = new List<Action>();

        /// <summary>
        /// 
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            inOut = new int[innerCounter, outerCounter];
            Program myProgram = new Program();

            try
            {
                for (int outer = 0; outer < outerCounter; outer++)
                {

                    for (int inner = 0; inner < innerCounter; inner++)
                        alSync.Add(() => myProgram.ThreadCall(new Elements(inner, outer)));

                    Parallel.Invoke(alSync.ToArray());                            
                    alSync.Clear();

                    Console.WriteLine("Main Thread Released Post Wait ...");
                    Console.WriteLine("Hit Count :: " + hitCount);
                    Console.WriteLine("Exception Count :: " + exceptionCount);
                }

            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception :: " + ex.Message);
            }
            finally
            {
                if (alSync != null)
                    alSync = null;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="state"></param>
        public void ThreadCall(object state)
        {
            try
            {
                Interlocked.Increment(ref hitCount);
                Elements localElement = (Elements)state;
                int localInner = localElement.innerValue;
                int localOuter = localElement.outerValue;
                int finalValue = inOut[localInner, localOuter];
            }
            catch (Exception ex)
            {
                Interlocked.Increment(ref exceptionCount);
                Console.WriteLine("Exception :: " + ex.Message);
            }

        }
    }
}

Task.Run(由于索引值超出数组而失败,尝试获取内部索引-500)

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace TestThreads
{
    /// <summary>
    /// 
    /// </summary>
    class Elements
    {
        public int innerValue;
        public int outerValue;

        public Elements(int innerValue, int outerValue)
        {
            this.innerValue = innerValue;
            this.outerValue = outerValue;
        }
    }

    /// <summary>
    /// 
    /// </summary>
    class Program
    {
        private static int innerCounter = 500;
        private static int outerCounter = 1000;
        private static int[,] inOut;
        private static int hitCount = 0;
        private static int exceptionCount = 0;

        private static List<Task> tlSync = new List<Task>();

        /// <summary>
        /// 
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            inOut = new int[innerCounter, outerCounter];
            Program myProgram = new Program();

            try
            {
                for (int outer = 0; outer < outerCounter; outer++)
                {                  

                    for (int inner = 0; inner < innerCounter; inner++)
                        tlSync.Add(Task.Run(() => myProgram.ThreadCall(new Elements(inner, outer))));

                    Task.WaitAll(tlSync.ToArray());
                    tlSync.Clear();

                    Console.WriteLine("Main Thread Released Post Wait ...");
                    Console.WriteLine("Hit Count :: " + hitCount);
                    Console.WriteLine("Exception Count :: " + exceptionCount);
                }

            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception :: " + ex.Message);
            }
            finally
            {               
                if (tlSync != null)
                    tlSync = null;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="state"></param>
        public void ThreadCall(object state)
        {
            try
            {
                Interlocked.Increment(ref hitCount);
                Elements localElement = (Elements)state;
                int localInner = localElement.innerValue;
                int localOuter = localElement.outerValue;
                int finalValue = inOut[localInner, localOuter];
            }
            catch (Exception ex)
            {
                Interlocked.Increment(ref exceptionCount);
                Console.WriteLine("Exception :: " + ex.Message);
            }           

        }
    }
}

Task.Factory.StartNew(由于索引值超出数组而失败,尝试获取内部索引-500)

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace TestThreads
{
    /// <summary>
    /// 
    /// </summary>
    class Elements
    {
        public int innerValue;
        public int outerValue;

        public Elements(int innerValue, int outerValue)
        {
            this.innerValue = innerValue;
            this.outerValue = outerValue;
        }
    }

    /// <summary>
    /// 
    /// </summary>
    class Program
    {
        private static int innerCounter = 500;
        private static int outerCounter = 1000;
        private static int[,] inOut;
        private static int hitCount = 0;
        private static int exceptionCount = 0;

        private static List<Task> tlSync = new List<Task>();

        /// <summary>
        /// 
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            inOut = new int[innerCounter, outerCounter];
            Program myProgram = new Program();

            try
            {
                for (int outer = 0; outer < outerCounter; outer++)
                {

                    for (int inner = 0; inner < innerCounter; inner++)
                        tlSync.Add(Task.Factory.StartNew(() =>  
myProgram.ThreadCall(new Elements(inner, outer))));

                    Task.WaitAll(tlSync.ToArray());
                    tlSync.Clear();

                    Console.WriteLine("Main Thread Released Post Wait ...");
                    Console.WriteLine("Hit Count :: " + hitCount);
                    Console.WriteLine("Exception Count :: " + exceptionCount);
                }

            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception :: " + ex.Message);
            }
            finally
            {
                if (tlSync != null)
                    tlSync = null;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="state"></param>
        public void ThreadCall(object state)
        {
            try
            {
                Interlocked.Increment(ref hitCount);
                Elements localElement = (Elements)state;
                int localInner = localElement.innerValue;
                int localOuter = localElement.outerValue;
                int finalValue = inOut[localInner, localOuter];
            }
            catch (Exception ex)
            {
                Interlocked.Increment(ref exceptionCount);
                Console.WriteLine("Exception :: " + ex.Message);
            }

        }
    }
}

不知道tlSync的用途是什么,我看不到为什么要将任务推送到通用列表。

如果您想做一些事情并更新用户界面,则可以从我曾经写过的表单程序中使用的这个功能中得到启发

var ui = TaskScheduler.FromCurrentSynchronizationContext();
someList
    .ForEach(f => Task.Factory.StartNew(() =>
    {
        // do stuff
    })
    .ContinueWith(task =>
    {
        if (task.IsCompleted)
        {
            // update UI
            // called after each task above completes
        }
    }, ui));

或者您可能对内部/外部有关闭问题,可以尝试更改此代码

for (int inner = 0; inner < innerCounter; inner++)
    tlSync.Add(Task.Factory.StartNew(() => myProgram.ThreadCall(new Elements(inner, outer))));

对此

for (int inner = 0; inner < innerCounter; inner++) {
    var nInner = inner;
    var nOuter = outer;
    tlSync.Add(Task.Factory.StartNew(() => myProgram.ThreadCall(new Elements(nInner, nOuter))));    
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM