RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 796118
Accepted
serjou
serjou
Asked:2020-03-10 21:33:46 +0000 UTC2020-03-10 21:33:46 +0000 UTC 2020-03-10 21:33:46 +0000 UTC

扫描注册表。递归和线程。C#

  • 772

再会!

我正在编写一个程序,我需要在其中扫描整个注册表。我决定递归地进行,就像我对文件和文件夹所做的那样,它们被扫描了大约 20 秒。结果,以下代码出现在某处:

class AllRegistryPermissions
    {
        public Dictionary<string, StringDictionary> HKCRKeys;
        public Dictionary<string, StringDictionary> HKCUKeys;
        public Dictionary<string, StringDictionary> HKLMKeys;

        static List<string> FPK;

        static public void GetRegistry(Dictionary<string, StringDictionary> Keys, RegistryKey ParentKey)
        {
            string Name = ParentKey.Name;
            if (!((Properties.Settings.Default.RFilterPathList.Contains(Name)) || (FPK.Any(t => Name.Contains(t)))))  //фильтрация по пути и по ключевым словам
            {
                if (ParentKey.ValueCount != 0)
                {
                    Keys.Add(ParentKey.Name, new StringDictionary());
                    foreach (string name in ParentKey.GetValueNames())
                    {
                        Keys[ParentKey.Name].Add(name, ParentKey.GetValue(name, "!!! Cant identify value !!!").ToString());
                    }
                }
                else Keys.Add(ParentKey.Name, null);

                if (ParentKey.SubKeyCount != 0)
                {
                    foreach (string name in ParentKey.GetSubKeyNames())
                    {
                        try
                        {
                            if (ParentKey.OpenSubKey(name) != null) GetRegistry(Keys, ParentKey.OpenSubKey(name));
                        }
                        catch (System.Security.SecurityException) { }
                    }
                }
            }
        }

        public AllRegistryPermissions()
        {
            FPK = Properties.Settings.Default.RFilterKeywordList.Cast<string>().ToList();
            HKCRKeys = new Dictionary<string, StringDictionary>();
            GetRegistry(HKCRKeys, Registry.ClassesRoot);
            HKCUKeys = new Dictionary<string, StringDictionary>();
            GetRegistry(HKCUKeys, Registry.CurrentUser);
            HKLMKeys = new Dictionary<string, StringDictionary>();
            GetRegistry(HKLMKeys, Registry.LocalMachine);
        }
    }

他扫描正常,但仅扫描一根树枝就HKCR需要五分钟。结果显然不适合我(因为同一个 Systracer 会在 20-30 秒内扫描所有内容),我考虑了多线程。经过长时间的巫术(我想我已经从一个heowolder至少成长为一个bydlocker),代码开始看起来像这样:

class AllRegistryPermissions
    {
        public ConcurrentDictionary<string, StringDictionary> HKCRKeys;
        public ConcurrentDictionary<string, StringDictionary> HKCUKeys;
        public ConcurrentDictionary<string, StringDictionary> HKLMKeys;

        static CountdownEvent ce;
        static int maxtasks = 0;
        static int cantopen = 0;
        static int cantopensec = 0;

        static List<string> FPK;

        static public void GetRegistry(ConcurrentDictionary<string, StringDictionary> Keys, RegistryKey ParentKey)
        {
            string Name = ParentKey.Name;
            if (!((Properties.Settings.Default.RFilterPathList.Contains(Name)) || (FPK.Any(t => Name.Contains(t)))))
            {
                int close = 0;
                if (ParentKey.ValueCount != 0) 
                {
                    ce.AddCount();
                    if (ce.CurrentCount > maxtasks) maxtasks = ce.CurrentCount;
                    Task.Run(() =>
                    {                        
                        Keys.GetOrAdd(ParentKey.Name, new StringDictionary());
                        foreach (string name in ParentKey.GetValueNames())
                        {
                            Keys[ParentKey.Name].Add(name, ParentKey.GetValue(name, "!!! Cant identify value !!!").ToString());
                        }
                        close++;
                        if (close == 2) ParentKey.Close();
                        ce.Signal();
                    });
                }
                else
                {
                    Keys.GetOrAdd(ParentKey.Name, (StringDictionary)null);
                    close++;
                }

                if (ParentKey.SubKeyCount != 0)
                {
                    ce.AddCount();
                    if (ce.CurrentCount > maxtasks) maxtasks = ce.CurrentCount;
                    Task.Run(() =>
                    {
                        foreach (string name in ParentKey.GetSubKeyNames())
                        {
                            try { if (ParentKey.OpenSubKey(name) != null) GetRegistry(Keys, ParentKey.OpenSubKey(name));
                                else cantopen++; }
                            catch (System.Security.SecurityException) {
                                cantopensec++; }
                        }
                        close++;
                        if (close == 2) ParentKey.Close();
                        ce.Signal();
                    });
                }
                else close++;
            }
        }

        public AllRegistryPermissions()
        {
            FPK = Properties.Settings.Default.RFilterKeywordList.Cast<string>().ToList();
            ce = new CountdownEvent(3);
            Task hkcrTask = Task.Run(() =>
            {
                HKCRKeys = new ConcurrentDictionary<string, StringDictionary>();
                GetRegistry(HKCRKeys, Registry.ClassesRoot);
                ce.Signal();
            });
            Task hkcuTask = Task.Run(() =>
            {
                HKCUKeys = new ConcurrentDictionary<string, StringDictionary>();
                GetRegistry(HKCUKeys, Registry.CurrentUser);
                ce.Signal();
            });
            Task hklmTask = Task.Run(() =>
            {
                HKLMKeys = new ConcurrentDictionary<string, StringDictionary>();
                GetRegistry(HKLMKeys, Registry.LocalMachine);
                ce.Signal();
            });            
             ce.Wait();
            Console.WriteLine("maximal tasks numbers: " + maxtasks);
            Console.WriteLine("can't open {0} subkeys", cantopen);
            Console.WriteLine("can't open {0} subkeys sec", cantopensec);
        }
    }

一切都会好起来的,但我觉得这一点都不好,也不对。我是第一次使用多线程,我不知道一次正常运行多少线程。谷歌搜索一点看到1-4。我的代码最多同时运行了130,000 个线程,我怀疑这非常糟糕(我以为计算机会爆炸)。但设计师在一分钟内完成了工作。
问题是,我该如何解决这个问题?不知何故重新编写代码,调节线程数,改变方法本身或用另一种语言重写代码(我听说C ++在这方面更快)?
该程序将使用该类的两个实例来比较并找出哪些键已被删除、添加或更改。

c#
  • 1 1 个回答
  • 10 Views

1 个回答

  • Voted
  1. Best Answer
    Vasek
    2020-03-11T17:16:22Z2020-03-11T17:16:22Z

    关于您的代码:

    • 它不起作用,因为没有正常的异常处理。当然,你把它卡在一个地方try catch,但这还不够。仔细阅读文档。
    • RegistryKey.OpenSubKey这是一个 api 调用的包装器,它相应地分配了一些 OS 对象。而这个对象在使用后需要释放。因此,类型RegistryKey为 IDisposable。您不仅不免费RegistryKey,而且还OpenSubKey两次调用合同。
    • 静态变量当然是一种方便的机制,但他们并没有想出它来模拟全局变量。如果您已经按照为您组织的方式创建静态方法,则将数据作为参数传递。否则,你会得到很大的悲伤,在最初的知识水平上很难捕捉到。此外,您的计数器不受任何方式的并行访问保护(阅读有关 Interlocked 和 Volatile 的信息)
    • 您使用的是任务,而不是线程。这些东西之间有很大的区别。因此,您有 130,000 个任务而不是 130,000 个线程。如果你有 130,000 个线程,那么很可能一切都崩溃了(嗯,至少在 32 位进程中)
    • 在您的情况下,您不需要创建如此大量的任务,这只会导致过度分配对象。你有足够的沿着溪流的每个分支(见我在下面的例子中是怎么做的)

    工作代码示例:

    阅读课:

    class RegData
    {
        public Dictionary<string, StringDictionary> HKCRKeys;
        public Dictionary<string, StringDictionary> HKCUKeys;
        public Dictionary<string, StringDictionary> HKLMKeys;
    
        public RegData()
        {
            HKLMKeys = new Dictionary<string, StringDictionary>();
            HKCRKeys = new Dictionary<string, StringDictionary>();
            HKCUKeys = new Dictionary<string, StringDictionary>();
        }
    
        public void ReadSingleThread()
        {
            Clear();
            var FPK = Properties.Settings.Default.RFilterPathList.Cast<string>().ToList();
    
            //GetRegistry(HKCRKeys, Registry.ClassesRoot, FPK);
            GetRegistry(HKCUKeys, Registry.CurrentUser, FPK);
            GetRegistry(HKLMKeys, Registry.LocalMachine, FPK);
        }
    
        public void ReadMultiThread()
        {
            Clear();
            var FPK = Properties.Settings.Default.RFilterPathList.Cast<string>().ToList();
    
            //var hkcrThread = RunThread(HKCRKeys, Registry.ClassesRoot, FPK);
            var hkcuThread = RunThread(HKCUKeys, Registry.CurrentUser, FPK);
            var hklmThread = RunThread(HKLMKeys, Registry.LocalMachine, FPK);
    
            //hkcrThread.Join();
            hkcuThread.Join();
            hklmThread.Join();
        }
    
        private void Clear()
        {
            HKLMKeys.Clear();
            HKCRKeys.Clear();
            HKCUKeys.Clear();
        }
    
        private Thread RunThread(Dictionary<string, StringDictionary> keys, RegistryKey parentKey, List<string> FPK)
        {
            var thread = new Thread(() => {
                try {
                    GetRegistry(keys, parentKey, FPK);
                }
                catch (Exception e) {
                    Console.WriteLine($"Thread proc for {parentKey.Name} fault: {e.Message}");
                }
            });
    
            thread.Start();
            return thread;
        }
    
        //###########
        //
        // Static
        //
        //###########
    
        static private void GetRegistry(Dictionary<string, StringDictionary> keys, RegistryKey parentKey, List<string> FPK)
        {
            string Name = parentKey.Name;
            if (Properties.Settings.Default.RFilterPathList.Contains(Name) || FPK.Any(t => Name.Contains(t))) {
                return;
            }
    
            AddValues(keys, parentKey);
            AddSubKeys(keys, parentKey, FPK);
        }
    
        static private void AddValues(Dictionary<string, StringDictionary> keys, RegistryKey parentKey)
        {
            string[] valueNames = null;
            if (!TryGetValueNames(parentKey, out valueNames)) {
                keys.Add(parentKey.Name, null);
                return;
            }
    
            var values = new StringDictionary();
            keys.Add(parentKey.Name, values);
            foreach (string name in valueNames) {
                values.Add(name, parentKey.GetValue(name, "error value").ToString());
            }
        }
    
        static private void AddSubKeys(Dictionary<string, StringDictionary> keys, RegistryKey parentKey, List<string> FPK)
        {
            string[] subKeyNames = null;
            if (!TryGetSubKeyNames(parentKey, out subKeyNames)) {
                return;
            }
    
            foreach (string subKeyName in subKeyNames) {
                RegistryKey subkey = null;
                if (TryOpenSubKey(parentKey, subKeyName, out subkey)) {
                    using (subkey) {
                        GetRegistry(keys, subkey, FPK);
                    }
                }
            }
        }
    
        static private bool TryGetValueNames(RegistryKey parentKey, out string[] valueNames)
        {
            valueNames = null;
    
            try {
                if (parentKey.ValueCount != 0) {
                    valueNames = parentKey.GetValueNames();
                }
            }
            catch (Exception e) {
                Console.WriteLine($"GetValueNames of {parentKey.Name} fail: {e.Message}");
            }
    
            return valueNames != null;
        }
    
        static private bool TryGetSubKeyNames(RegistryKey parentKey, out string[] subKeyNames)
        {
            subKeyNames = null;
    
            try {
                if (parentKey.SubKeyCount != 0) {
                    subKeyNames = parentKey.GetSubKeyNames();
                }
            }
            catch (Exception e) {
                Console.WriteLine($"GetSubKeyNames of {parentKey.Name} fail: {e.Message}");
            }
    
            return subKeyNames != null;
        }
    
        static private bool TryOpenSubKey(RegistryKey parentKey, string subKeyName, out RegistryKey subKey)
        {
            subKey = null;
    
            try {
                subKey = parentKey.OpenSubKey(subKeyName);
                if (subKey == null) {
                    Console.WriteLine($"OpenSubKey({subKeyName}) of {parentKey.Name} generic fail");
                }
            }
            catch (System.Security.SecurityException) {
                // антиспам
            }
            catch (Exception e) {
                Console.WriteLine($"OpenSubKey({subKeyName}) of {parentKey.Name} fail: {e.Message}");
            }
    
            return subKey != null;
        }
    }
    

    使用示例:

    static void Main(string[] args)
    {
        TestSingleThread();
        TestMultiThread();
    
        TestSingleThread();
        TestMultiThread();
    
        TestSingleThread();
        TestMultiThread();
    
        Console.ReadKey();
    }
    
    static void TestSingleThread()
    {
        var sw = new Stopwatch();
        sw.Start();
    
        var t = new RegData();
        t.ReadSingleThread();
    
        sw.Stop();
        Console.WriteLine($"Singlethread done: {sw.ElapsedMilliseconds}");
    }
    
    static void TestMultiThread()
    {
        var sw = new Stopwatch();
        sw.Start();
    
        var t = new RegData();
        t.ReadMultiThread();
    
        sw.Stop();
        Console.WriteLine($"Multithread done: {sw.ElapsedMilliseconds}");
    }
    

    关于速度:

    我测试了您的代码和我的代码,它们在速度方面大致相同。平均而言,单线程模式读取我需要 10-20 秒;在多线程模式下,由于我的HKEY_LOCAL_MACHIN分支很大,其余的很小,因此速度并没有增加太多。

    总的来说,我没有像你那样达到如此糟糕的指标。我用谷歌搜索了一下,发现了这个和这个。简而言之...

    • 操作系统可以缓存对注册表的访问,因此,在访问一定次数后,访问应该会加快。尝试多次运行代码,性能可以大大提高
    • 第一个链接说 HKEY_CLASSES_ROOT 分支可能由于名称过长而存在速度问题。到目前为止,我已经在速度方面与我一起测试过它,它与其他的没有什么不同。但是你可能会有不同的结果,尝试爬取排除这个分支。

    关于 C++:

    加号当然是一种强大的语言,通常它上面的代码会更快。但是您对操作系统功能的调用非常密集,而且很明显,优点不会在速度上产生任何大的差异。此外,复杂的语言和用它写作的优势,那么你已经写了,会花费你更多的时间和精力,而且收益可能会是一分钱。

    • 1

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    是否可以在 C++ 中继承类 <---> 结构?

    • 2 个回答
  • Marko Smith

    这种神经网络架构适合文本分类吗?

    • 1 个回答
  • Marko Smith

    为什么分配的工作方式不同?

    • 3 个回答
  • Marko Smith

    控制台中的光标坐标

    • 1 个回答
  • Marko Smith

    如何在 C++ 中删除类的实例?

    • 4 个回答
  • Marko Smith

    点是否属于线段的问题

    • 2 个回答
  • Marko Smith

    json结构错误

    • 1 个回答
  • Marko Smith

    ServiceWorker 中的“获取”事件

    • 1 个回答
  • Marko Smith

    c ++控制台应用程序exe文件[重复]

    • 1 个回答
  • Marko Smith

    按多列从sql表中选择

    • 1 个回答
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Suvitruf - Andrei Apanasik 什么是空? 2020-08-21 01:48:09 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5