Why there is no runtime difference between multi-threaded and single-threaded

I am trying to learn the python language and its concept. I wrote some codes for multithreading. But I notice that there is no difference in runtime between multiple and single threads.

The machine that should run the script has 4 cores / thread.

def get_tokens(file_name,map): print(file_name) counter = 0 with open(file_name,'r',encoding='utf-8-sig') as f: for line in f: item = json.loads(line,encoding='utf-8') if 'spot' in item and item['sid'] == 4663: counter+=1 if counter == 500: break tokens = nltk.word_tokenize(item['spot'],language='english') for token in tokens: if token not in map: map[token] = 1 else: map[token] = map[token] + 1; start_time = time.time() map = dict(); with ThreadPoolExecutor(max_workers=3) as executor: for file in FileProcessing.get_files_in_directory('D:\\Raw Data'): future = executor.submit(FileProcessing.get_tokens, file, map) end_time = time.time() print("Elapsed time was %g seconds" % (end_time - start_time)) 

The size of each file in Raw Data strong> is greater than 25 mb. Therefore, I believe that this is the difference between the two. But no. What for? Am I making a mistake in the concept of code or multithreading?

+6
source share
5 answers

CPython (the standard Python implementation) does not support multithreading on different processors. Thus, you can actually have several threads, but all of them will work on one processor, and you will not have speed improvements for processes related to processors (you would have associated processes with I / O binding).

The reason for this is the infamous GIL (global interpreter lock). The Python kernel is not thread safe due to the way it does garbage collection, so it uses a lock, which means that threads accessing python objects are started one after another.

In your specific case, you are doing some I / O and some processing. When performing multiprocessing in python, significant overhead is not compensated by the gain in I / O speed (the time to read files is probably small compared to the time they were processed).

If you need to do a real multi-threaded view in Cython (not to be confused with CPython) and "no_gil", or c-extensions, or a multiprocessing module.

+5
source

Python has a Global Interpretor Lock (GIL) that prevents two threads from executing in the same python process at the same time. Therefore, although python threads provide you with multiple control paths within a single process, multiple control paths cannot be executed simultaneously on a multi-core machine. An alternative is to use python's multiprocessing infrastructure , which will actually create separate processes and then bind processes through interprocess communication (IPC). You can also try using the ProcessPoolExecutor , which will spawn multiple processes, and so you won't have a problem with the GIL

+2
source

The GIL comments are correct, but this code is more likely to be related to IOs than to CPU bindings.

Even if you used something like C or Java, you are still reading files through the serial interface, so if you cannot handle 100-300 MB / s JSON, you will not see the performance benefits of streaming.

@DevShark said that you will see an advantage for IO-bound processes, but it's harder than that. This is usually more for simultaneous high latency network connections. In this case, you should be bound to the IO on the disk, and not to the process (you do not expect a response to the remote response), so parallelism will not help.

If you are attached to a processor, have real threads and use a spinning disk, you still need to carefully adjust the buffer sizes. A search time of 10 ms can kill you, so you need to use buffered reads with buffer sizes much larger than this if you want high disk bandwidth. With a 100 MB / s disk with a 10 ms search time, I would use 10 MB buffers, but that still means that you spend 10% of your time on the disk. I would also coordinate my readings, so only one reader reads.

+2
source

The problem is whether the code can be improved by streaming. If the code is serial and one after the other in a straight line, then the code will work the same regardless of how many threads you have. However, if the code can separate and execute action a and action b at the same time, this will happen. Stepping closer to your code, it seems like there is no branching, at least I don't know.

+1
source

Your code is tied to a processor - multithreading will remain within the same processor by default. You can use the package a multiprocessor package that allows you to create subprocesses and, in essence, bypass GIL (Global Interpreter Lock). Of course, this will only help if you have multiple processors. And I do not think that the overhead of several processes is justified for this use case.

+1
source

Source: https://habr.com/ru/post/989699/


All Articles