windows - Programmet går langsommere i en tråd sammenlignet med enkeltstående udførelse

Indlæg af Hanne Mølgaard Plasc

Problem



import winreg
from threading import Thread
from constants import keynames
import time


class Dumper(object):
    """
    Description: A class containing functions to dump all the registry values for the specified key.
    """
    def \_\_init\_\_(self, file\_encoding='utf-8'):
        self.file\_encoding = file\_encoding

    def open\_registry(self, key=winreg.HKEY\_LOCAL\_MACHINE, subkey="", file\_name='reg\_dump.txt'):
        """
        Description: A function meant to initiate the procedure of dumping registry, from the root key specified by the
                     user.
        Argument(s):
            key: any of the 7 main root keys of the windows registry.
                  e.g: HKEY\_LOCAL\_MACHINE, HKEY\_CLASSES\_ROOT... etc.
            subkey: The subkey to be iterated over.
                    e.g: HKEY\_CURRENT\_USERAppEventsEventLabels.Default,
                         HKEY\_CURRENT\_USERAppEventsEventLabels ...       etc.
            file\_name: Name of the file in which to take the dump.
        """
        try:
            start\_time = time.time()
            with winreg.OpenKey(key, subkey, 0) as hkey:
                with open(file\_name, "a+", encoding=self.file\_encoding) as dump\_file:
                    specified\_key = keynames.get(key, "ERROR: INVALID KEY.")
                    root\_key = "Root Key: {}".format(specified\_key)
                    if dump\_file.readline():
                        root\_key = "
Root Key: {}".format(specified\_key)
                    dump\_file.write(root\_key)
                    self.\_\_traverse\_registry(hkey, dump\_file, parent\_key=specified\_key)
            exec\_time = divmod((time.time() - start\_time), 60)
            key\_name = keynames.get(key)
            print("For key {}: 
execution time: {mins:.0f} minute(s) and "
                  "{secs:.4f} second(s)".format(key\_name, mins=exec\_time[0], secs=exec\_time[1]))
        except OSError as oserr:
            print("
Key: {}	Subkey: {}
".format(key, subkey))
        except Exception as ex:
            print("Error: {}".format(ex))

    def \_\_traverse\_registry(self, key=None, file\_handle=None, parent\_key=None):
        """
        Description: A private function to iterate over the registry database to list all the values in a key and repeat
        the process for all nested sub keys.
        Argument(s):
            key: The root key(or sub key) to be iterated over.
                 e.g.: HKEY\_LOCAL\_MACHINE, HKEY\_LOCAL\_MACHINEBCD00000000... etc.
            file\_handle: Open handle of the file in which to dump the registry.
            parent\_key: Name of the parent,so that the sub key can be recorded with path.
                        e.g.: HKEY\_LOCAL\_MACHINEBCD00000000, HKEY\_LOCAL\_MACHINESOFTWARE... etc.
        """
        if not any([key, file\_handle, parent\_key]):
            raise ValueError("One or more essential parameters not found:
key: {}
file\_handle: {}"
                             "
parent\_key: {}".format(key, file\_handle, parent\_key))
        q\_info = winreg.QueryInfoKey(key)
        lst\_records = list()
        if q\_info[1]:
            for i in range(q\_info[1]):
                value\_name = winreg.EnumValue(key, i)[0]
                value\_data = winreg.EnumValue(key, i)[1]
                value\_type = winreg.EnumValue(key, i)[2]
                record = "
		Value {}
		Name: {}
		Data: {}" 
                         "
		Type: {}".format(i, value\_name, str(value\_data), value\_type)
                lst\_records.append(record)
                #file\_handle.write(record)
            file\_handle.writelines(lst\_records)
            del lst\_records

        if q\_info[0]:
            for i in range(q\_info[0]):
                subkey = winreg.EnumKey(key, i)
                try:
                    file\_handle.write("
	{}".format("\".join([parent\_key, subkey])))
                    with winreg.OpenKey(key, subkey, 0) as open\_subkey:
                        self.\_\_traverse\_registry(open\_subkey, file\_handle, "\".join([parent\_key, subkey]))
                except PermissionError as pex:
                    # We continue with the code despite the issue since some keys don't have permissions in the user
                    # mode.
                    file\_handle.write("
	PERMISSIONS ERROR: {}".format(pex.strerror))
                    continue
                except FileNotFoundError as ferr:
                    file\_handle.write("
Parent\_key: {}	SubKey: {}
	FILENOTFOUND ERROR: {}".format(parent\_key, subkey,
                                                                                         ferr.strerror))
                    continue
                except Exception as generic\_ex:
                    # Log any other exceptions that occur.
                    file\_handle.write("
	ERROR: {}".format(generic\_ex))
                    continue


def create\_dumper\_instances(subkey=""):
    """
    Description: A function to create and run threads with a delay specified in the constants.
    Argument(s):
        key: The root key from which to start recording the dump.
             e.g: HKEY\_CLASSES\_ROOT, HKEY\_CURRENT\_USER...
        subkey: If provided, dumping will take place only for that specific subkey.
                e.g: HKEY\_CURRENT\_USERVolatile Environment, HKEY\_CURRENT\_USERSoftware ...
    """
    for i, key in enumerate(keynames.keys()):
        file\_name = "reg\_dump\_{}.txt".format(keynames[key])
        dumper\_instance = Dumper()
        thread = Thread(target=dumper\_instance.open\_registry, args=(key, subkey, file\_name))
        thread.start()



if \_\_name\_\_ == "\_\_main\_\_":
    create\_dumper\_instances()
    #Depending upon the root key provided(how deep it is), the creation time of dump files can
    #vary from 5 seconds to 42 seconds.

    #dumper = Dumper()
    #dumper.open\_registry(winreg.HKEY\_CLASSES\_ROOT, file\_name="reg\_dump\_{}.txt".format(keynames[winreg.HKEY\_CLASSES\_ROOT]))


Så her forsøger jeg at tage et dump af alle 5 registreringsdatabasenøgler i Windows-registreringsdatabasen. Men når jeg laver tråde tager det 1 min. 45 sekunder at gennemføre (især for HKLM) og for den samme nøgle, hvis den udføres selvstændigt, så tager det 45 sekunder.


På trods af debugging er det stadig ikke klart, hvorfor det tager længere tid med tråde end selvstændig udførelse. Enhver hjælp ville blive værdsat.


Yderligere information:


keynames = {
    winreg.HKEY\_LOCAL\_MACHINE: "HKEY\_LOCAL\_MACHINE",
    winreg.HKEY\_CLASSES\_ROOT: "HKEY\_CLASSES\_ROOT",
    winreg.HKEY\_CURRENT\_CONFIG: "HKEY\_CURRENT\_CONFIG",
    winreg.HKEY\_CURRENT\_USER: "HKEY\_CURRENT\_USER",
    winreg.HKEY\_USERS: "HKEY\_USERS"
}

Bedste reference