首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用条件锁定控制并行性?

用条件锁定控制并行性?
EN

Stack Overflow用户
提问于 2013-12-14 06:43:39
回答 1查看 119关注 0票数 1

总之,我有一个递归任务,我想使用我所有的4个处理器来更快地处理这棵大树。我目前的生产实现使用Parallel.ForEach,并且失去控制,将我的所有4个cpus连接起来,并且很快就失去了内存。所以,我知道正确的算法可以给我所有的4个cpus 70%-80%,我发现这将使爬行工作迅速完成,同时离开用户界面响应和我的电脑整体响应轻用户界面驱动的任务。此任务是后台任务。

我正在尝试的方法(下面列出)是并行的和递归的,我希望使用条件锁来限制线程。

我希望这段代码使用最多4个线程来保持递归创建20个可怕的头,直到在所有分支中达到10的嵌套深度。我把它从2头改为20头,因为这更像是我的实际问题。我的实际树只有4-5层深,但相当宽,每个节点都需要比Console.WriteLine更多的cpu。

要做到这一点并不像我想象的那样容易。

我试图让所有大于4的线程等待,直到完成之前出现的足够多的线程将线程总数降回4个,然后再继续。因此,如果创建了几个以上的线程,只要那些> #4的线程只是等待,就可以了。因此,有条件等待(锁定)部分。

我的代码示例显然只是为了概念目的,也正是我尝试过的。请随意偏离我的实现细节。

编辑:我昨晚改变了我的实现,使用SemaphoreSlim,一个胖男孩的表弟,苗条,来处理交警的角色。这只会导致两个处理器在20%的时间里忙碌。

我的下一次迭代可能需要循环四次来创建4个工作人员,它们彼此独立地爬行节点。但困难在于,他们需要知道哪些节点(子树)目前正在爬行,或者已经被其他工作人员爬行。我不确定这是否比下面的方法要简单。所列出的方法似乎确实避免了按错误的顺序处理节点(例如,父级之前的子节点),但可能这只是代码结构外观所造成的幻觉。

代码语言:javascript
复制
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

    public class ScaryTeddy
    {
        public ScaryTeddy(ScaryTeddy parent, int position)
        {
            Parent = parent;
            Position = position;
            DoSomethingHeavy();
        }

        public BlockingCollection<ScaryTeddy> Heads = new BlockingCollection<ScaryTeddy>();
        public ScaryTeddy Parent { get; set; }
        private string _path;
        public string Path
        {
            get
            {
                if (_path == null)
                {
                    if (Parent != null)
                        _path = string.Format("{0}.{1}", Parent.Path, Position);
                    else
                        _path = Position.ToString();
                }
                return _path;
            }
        }

        public int Position { get; set; }

        // short in duration but taxing on cpu and memory
        private static void DoSomethingHeavy()
        {
            // look at all the text inside every jpg in my pictures. Admire my girl friend's beauty!
            FileSystem.FindInFilesFileList(@"C:\Documents\Pictures", new List<string>() { "Exif" }, new List<string>() { "*.jpg" }, null, null);
        }

        // these have to be static b/c CreateScaryTeddy is static
        private static readonly SemaphoreSlim SemaphoreSlim = new SemaphoreSlim(4, 4); // 4 cpus
        private static object _lock = new object(); // one object for all instances? Is that correct?
        private static int _scaryTeddyFactories = 0; // just a way to inspect how many are concurrent

        // this only produces 2 cpus working at about 20%; I want all 4 working at 70-80%
        public static ScaryTeddy CreateScaryTeddy(ScaryTeddy parent = null, int position = 1)
        {
            SemaphoreSlim.Wait();
            lock (_lock) _scaryTeddyFactories++;
            var scaryTeddy = new ScaryTeddy(parent, position);
            Console.WriteLine("Thread {0} with slot {1} created Scary Teddy {2}", Thread.CurrentThread.ManagedThreadId, _scaryTeddyFactories, scaryTeddy.Path);
            lock (_lock) _scaryTeddyFactories--;
            SemaphoreSlim.Release();

            if (scaryTeddy.Path.Split(".".ToCharArray()).Length <= 10)
            {
                Parallel.For(0, 20,
                    new ParallelOptions { MaxDegreeOfParallelism = 2 },
                    babyHead => scaryTeddy.Heads.Add(CreateScaryTeddy(scaryTeddy, babyHead)));
            }

            return scaryTeddy;
        }
    }

编辑:结果

所有4个处理器几乎都挂了-完美!

控制台输出显示涉及一个线程池。我想信号量的工作方式是开放的插槽总是#4?

代码语言:javascript
复制
Thread 1 with slot 1 created Scary Teddy 1
Thread 6 with slot 2 created Scary Teddy 1.10
Thread 1 with slot 3 created Scary Teddy 1.0
The thread '<No Name>' (0x1668) has exited with code 0 (0x0).
The thread '<No Name>' (0x3bd0) has exited with code 0 (0x0).
Thread 5 with slot 4 created Scary Teddy 1.10.0
Thread 1 with slot 4 created Scary Teddy 1.0.10
Thread 6 with slot 4 created Scary Teddy 1.10.10
Thread 3 with slot 4 created Scary Teddy 1.0.0
Thread 5 with slot 4 created Scary Teddy 1.10.0.0
Thread 1 with slot 4 created Scary Teddy 1.0.10.0
Thread 9 with slot 4 created Scary Teddy 1.0.10.10
Thread 6 with slot 4 created Scary Teddy 1.10.10.0

我们有4个线程在做工作,这正是我想要的,而池的其余部分正在等待,IMHO并不太多。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-12-14 11:44:25

将您的outOfControl节流机制替换为new SemaphoreSlim(4)。这是内置的框架。(此外,您正在读取_scaryTeddyFactoryCount,而不使用不安全的锁定。但当你使用信号量时,这种情况就消失了。)

使静态变量实例变量。目前,它们的价值观在所有实例之间都是危险的共享。

您可能希望切换到异步等待样式(例如使用async/awaitContinueWith)来使用更少的线程。递归树非常大,最终可能会有很多线程在等待信号量。甚至可能耗尽线程池和死锁。

您正在以不同步的方式向集合(scaryTeddy.Heads.Add)添加项。那是不安全的。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20580515

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档