需要帮助调整C#多线程例程

时间:2019-12-02 18:15:43

标签: c# multithreading

我创建了一个Windows服务,该服务使用Parallel.ForEach在具有24个核心,48个虚拟虚拟机的计算机上运行多线程例程。该服务在生产环境中一直运行良好,可以将数据批量复制到SQL Server数据库中。目前,它的性能非常好,每秒大约有6000次插入,但是我相信可以对其进行调整。以下是我正在使用的部分代码;有一个当前功能的示例,并提出了调整建议。从代码中可以看出,当前对Add的每次调用都采用了锁定,我认为这会使Parallel.ForEach有点不平行。因此,我正在寻找“解决方案”;希望代码中也定义了我的新方法,可以解决问题。


    public class MainLoop
    {
        public void DoWork()
        {
            var options = new ParallelOptions
            {
                MaxDegreeOfParallelism = System.Environment.ProcessorCount * 2
            };

            var workQueueManager = new ObjWorkQueueManager(queueSize: 1000);

            // ignore the fact that this while loop would be a never ending loop,
            // there's other logic not shown here that exits the loop!
            while (true)
            {
                ICollection<object> work = GetWork();

                Parallel.ForEach(work, options, (item) =>
                {
                    workQueueManager.AddOLD(item);
                });
            }
        }

        private ICollection<object> GetWork()
        {
            // return list of work from some arbitrary source
            throw new NotImplementedException();
        }
    }

    public class ObjWorkQueueManager
    {
        private readonly int _queueSize;
        private ObjDataReader _queueDataHandler;
        private readonly object _sync;

        public ObjWorkQueueManager(int queueSize) 
        {
            _queueSize = queueSize;
            _queueDataHandler = new ObjDataReader(queueSize);
            _sync = new object();
        }

        // current Add method works great, but blocks with EVERY call
        public void AddOLD(object value)
        {
            lock (_sync)
            {
                if (_queueDataHandler.Add(value) == _queueSize)
                {
                    // create a new thread to handle copying the queued data to repository
                    Thread t = new Thread(SaveQueuedData);
                    t.Start(_queueDataHandler);

                    // start a new queue 
                    _queueDataHandler = new ObjDataReader(_queueSize);
                }
            }
        }

        // hoping for a new Add method to work better by blocking only 
        // every nth call where n = _queueSize
        public void AddNEW(object value)
        {
            int queued;
            if ((queued = _queueDataHandler.Add(value)) >= _queueSize)
            {
                lock (_sync)
                {
                    if (queued == _queueSize)
                    {
                        Thread t = new Thread(SaveQueuedData);
                        t.Start(_queueDataHandler);
                    }
                }
            }
            else if (queued == 0)
            {
                lock (_sync)
                {
                    _queueDataHandler = new ObjDataReader(_queueSize);

                    AddNEW(value);
                }
            }
        }

        // this method will Bulk Copy data into an SQL DB
        private void SaveQueuedData(object o)
        {
            // do something with o as ObjDataReader
        }
    }

    // implements IDataReader, Read method of IDataReader dequeues from _innerQueue
    public class ObjDataReader
    {
        private readonly int _capacity;
        private Queue<object> _innerQueue;

        public ObjDataReader(int capacity)
        {
            _capacity = capacity;
            _innerQueue = new Queue<object>(capacity);
        }

        public int Add(object value)
        {
            if (_innerQueue.Count < _capacity)
            {
                _innerQueue.Enqueue(value);
                return _innerQueue.Count;
            }

            return 0;
        }
    }

0 个答案:

没有答案