Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net 使用条件锁定控制并行性?_.net_Multithreading_C# 4.0_Recursion_Locking - Fatal编程技术网

.net 使用条件锁定控制并行性?

.net 使用条件锁定控制并行性?,.net,multithreading,c#-4.0,recursion,locking,.net,Multithreading,C# 4.0,Recursion,Locking,总而言之,我有一个递归任务,我想使用我所有的4个处理器来更快地处理这棵大树。我当前的生产实现使用了Parallel.ForEach,失去了控制,占用了我所有的4个CPU,很快就耗尽了内存。因此,我知道正确的算法可以以70-80%的速度为我提供所有4个CPU,我发现这样可以快速完成爬行任务,同时让UI响应性和我的计算机整体响应性更好,以完成轻UI用户驱动的任务。此任务是后台任务 我尝试的方法(如下所列)是并行和递归的,我想使用条件锁来限制线程 我希望这段代码最多使用4个线程来递归地创建20个可怕的

总而言之,我有一个递归任务,我想使用我所有的4个处理器来更快地处理这棵大树。我当前的生产实现使用了
Parallel.ForEach
,失去了控制,占用了我所有的4个CPU,很快就耗尽了内存。因此,我知道正确的算法可以以70-80%的速度为我提供所有4个CPU,我发现这样可以快速完成爬行任务,同时让UI响应性和我的计算机整体响应性更好,以完成轻UI用户驱动的任务。此任务是后台任务

我尝试的方法(如下所列)是并行和递归的,我想使用条件锁来限制线程

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

这并不像我想象的那么容易实现

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

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

编辑:我昨晚更改了我的实现,使用信号量lim(胖男孩斯利姆的表弟)来处理交通警察的角色。它只会导致两个处理器以20%的速度忙碌

我的下一次迭代可能会涉及四次循环,以创建4个独立于其他节点抓取节点的worker。但困难在于,他们需要知道哪些节点(子树)当前正在被爬网,或者已经被另一个工作者爬网。我不确定这是否比下面的方法简单。所列出的方法似乎确实避免了以错误的顺序处理节点(例如,子节点在父节点之前),但这可能只是代码结构外观带来的错觉

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;
        }
    }
使用系统;
使用系统集合;
使用System.Collections.Generic;
使用System.Linq;
使用系统线程;
使用System.Threading.Tasks;
公共级Scarytedy
{
公共ScaryTeddy(ScaryTeddy父级,内部位置)
{
父母=父母;
位置=位置;
DoSomethingHeavy();
}
public BlockingCollection Heads=new BlockingCollection();
公共scarytedy父项{get;set;}
私有字符串路径;
公共字符串路径
{
得到
{
如果(_path==null)
{
如果(父项!=null)
_path=string.Format(“{0}.{1}”,Parent.path,Position);
其他的
_路径=位置.ToString();
}
返回路径;
}
}
公共int位置{get;set;}
//持续时间短,但占用cpu和内存
私有静态无效DoSomethingHeavy()
{
//看看我照片中每个jpg里面的文字。欣赏我女朋友的美丽!
FindInFilesFileList(@“C:\Documents\Pictures”,new List(){“Exif”},new List(){“*.jpg”},null,null);
}
//这些必须是静态的b/c CreateCaryteddy是静态的
私有静态只读信号量lim SemaphoreSlim=新信号量lim(4,4);//4个CPU
私有静态对象_lock=new object();//所有实例一个对象?正确吗?
private static int\u scarytedfactories=0;//这只是一种检查有多少是并发的方法
//这只会产生2个CPU,工作速度约为20%;我希望所有4个CPU的工作速度均为70-80%
公共静态ScaryTeddy CreateScaryTeddy(ScaryTeddy父项=null,内部位置=1)
{
SemaphoreSlim.Wait();
锁(_lock)_scarytedyFactorys++;
var scaryTeddy=新scaryTeddy(父级,位置);
WriteLine(“插槽为{1}的线程{0}创建了{2}”、Thread.CurrentThread.ManagedThreadId、_scarytedFactorys、scaryTeddy.Path);
锁(_lock)_scarytedy工厂--;
SemaphoreSlim.Release();
if(scaryTeddy.Path.Split(“.”.ToCharArray()).Length scarytedy.Heads.Add(CreateScaryTeddy(scaryTeddy,babyHead));
}
返回scarytedy;
}
}
编辑:结果

所有4个处理器几乎都被锁定-完美

控制台输出显示涉及线程池。我猜信号灯的工作方式是打开的插槽总是#4

线程1与插槽1一起创建
带插槽2的螺纹6创建了Teddy 1.10
带有插槽3的线程1已创建为Teddy 1.0
线程“”(0x1668)已退出,代码为0(0x0)。
线程“”(0x3bd0)已退出,代码为0(0x0)。
带插槽4的螺纹5由Teddy 1.10.0创建
带插槽4的螺纹1创建于Teddy 1.0.10
螺纹6和槽4创建于Teddy 1.10.10
带插槽4的线程3已创建为Teddy 1.0.0
螺纹5和插槽4创建在Teddy 1.10.0.0中
带插槽4的螺纹1创建于Teddy 1.0.10.0
带插槽4的螺纹9由Teddy 1.0.10.10创建
螺纹6和插槽4创建在Teddy 1.10.10.0中


我们有4个线程在工作,这正是我想要的,而池中的其他线程正在等待,这并不太多。

用新的信号量lim(4)替换您的
失控的
节流机制。这是框架内置的。(另外,您正在读取
\u scaryTeddyFactoryCount
,但未锁定
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