notice that at all times we try to minimize the amount of work done within the scope of lock to keep blocking to minimum--in this case just one dictionary access each time gil strictly speakingwe do not need to use lock at all if we are using cpythonsince the gil effectively synchronizes dictionary accesses for us howeverwe have chosen to program without relying on the gil implementation detailand so we use an explicit lock for filenames in md values()if len(filenames= continue self results_queue put("{ }duplicate files ({ :nbytes):"\ \ { }format(self numbersize"\ \tjoin(sorted(filenames)))at the end we loop over the local md default dictionaryand for each set of names that contains more than one name we add multiline string to the results queue the string contains the worker thread number (an empty string by default)the size of the file in bytesand all the duplicate filenames we don' need to use lock to access the results queue since it is queue queue which will automatically handle the locking behind the scenes the queue module' classes greatly simplify threaded applicationsand when we need to use explicit locks the threading module offers many options here we used the simplestthreading lockbut others are availableincluding threading rlock ( lock that can be acquired again by the thread that already holds it)threading semaphore ( lock that can be used to protect specific number of resources)and threading condition that provides wait condition using multiple threads can often lead to cleaner solutions than using the subprocess modulebut unfortunatelythreaded python programs do not necgil essarily achieve the best possible performance compared with using multiple processes as noted earlierthe problem afflicts the standard implementation of pythonsince the cpython interpreter can execute python code on only one processor at timeeven when using multiple threads one package that tries to solve this problem is the multiprocessing moduleand as we noted earlierthe grepword- py program is multiprocessing version of the grepword- py programwith only three lines that are different similar transformation could be applied to the findduplicates- py program reviewed herebut in practice this is not recommended although the multiprocessing module offers an api (application programming interfacethat closely matches the threading module' api to ease conversionthe two apis are not the same and have different trade-offs alsoperforming mechanistic conversion from threading to multiprocessing is likely to be successful only on smallsimple programs like grepword- pyit is too crude an approach to use for the