this code consists of function named find_files that is run in separate thread (or processif we used processpoolexecutorthere isn' anything particularly special about this functionbut note how it does not access any global variables all interaction with the external environment is passed into the function or returned from it this is not technical requirementbut it is the best way to keep your brain inside your skull when programming with futures accessing outside variables without proper synchronization results in something called race condition for exampleimagine two concurrent writes trying to increment an integer counter they start at the same time and both read the value as then they both increment the value and write back the result as but if two processes are trying to increment variablethe expected result would be that it gets incremented by twoso the result should be modern wisdom is that the easiest way to avoid doing this is to keep as much state as possible private and share them through known-safe constructssuch as queues we set up couple variables before we get startedwe'll be searching for all files that contain the characters pyfor this example we have queue of futures that we'll discuss shortly the basedir variable points to the root of the filesystem'/on unix machines and probably :on windows firstlet' have short course on search theory this algorithm implements breadth first search in parallel rather than recursively searching every directory using depth first searchit adds all the subdirectories in the current folder to the queuethen all the subdirectories of each of those folders and so on the meat of the program is known as an event loop we can construct threadpoolexecutor as context manager so that it is automatically cleaned up and its threads closed when it is done it requires max_workers argument to indicate the number of threads running at timeif more than this many jobs are submittedit queues up the rest until worker thread becomes available when using processpoolexecutorthis is normally constrained to the number of cpus on the machinebut with threadsit can be much higherdepending how many are waiting on / at time each thread takes up certain amount of memoryso it shouldn' be too highit doesn' take all that many threads before the speed of the diskrather than number of parallel requestsis the bottleneck