简体   繁体   中英

Same callback, multiple threads

If I create multiple threads and I pass the same exact callback to all the threads, will these threads be executing the same block of memory (same function/callback) at the same time? Are thread callbacks passed by value or by reference? And is this a language dependent feature? How would this work in Python due to the Global Interpreter lock vs a language such as C#?

The below code shows different thread ID's being printed but what about the function location? Are there copies being made of LongOperation or is each thread accessing the same memory location each time their code is being run?

Example code in python:

def LongOperation():
    print( "Spinning up a thread with this ID: " + str(threading.get_ident()))
    print("Finishing up thread ID: " + str(threading.get_ident()))

i = 0
while i < 10:
    threading.Thread(target=LongOperation).start()
    i = i + 1

Thanks for reading.

Functions are compiled into code objects. LongOperation is a variable referencing one of those code blocks. Each time LongOperation is called, python creates a frame object that will hold the local variables unique to that single call. Although the frame object would be considered "call by reference" since a unique frame is created for each call, no other function is going to reference it. The exception is that if your function has a yield . Then you have a generator that could be passed to many other functions.

In your case, each thread accesses the same function object for the code, but separate frame objects for the data. This is very much like C where many callers would get the same code but different stack frames for data.

CPython only executes byte codes when a thread has acquired the GIL. It will release the GIL periodically to let threads interleave, but only one gets to execute at a time. Python extensions (either in python's stdlib - eg, regular expressions, or external, eg, numpy) are free to release the GIL if they want to. Its not required and when it is performant to release the GIL is kinda a personal opinion. CPython also releases the GIL when it does a blocking operation such as read a file.

If you have pure python that doesn't use GIL-releasing extensions and does not do I/O, multithreading is no faster than doing things sequentially. But if your code does those things, multithreading may help.

Python's async support is good for dealing with blocking things like file system or network access. It naturally scales up to completely committing 1 cpu to your program without the complications of managing multiple threads in a more traditional program.

If you do large numerical processing with a package that releases the GIL, multithreading gets interesting again because your program can consume multiple CPUs.

  • If I create multiple threads and I pass the same exact callback to all the threads, will these threads be executing the same block of memory (same function/callback) at the same time?

    yes, they use the same program code

  • Are thread callbacks passed by value or by reference?

    each thread could have its local variable

  • And is this a language dependent feature?

    not sure, but I think so.

  • How would this work in Python due to the Global Interpreter lock vs a language such as C#?

    I don't think it's related with GIL, you could still use multi-thread Python for highly IO (not CPU) work.

For your code, I do a test on that:

import threading
import time

def LongOperation(i):
    print("Spinning up a thread with this ID: " + str(threading.currentThread()))
    print("Finishing up thread ID: " + str(threading.currentThread().ident))
    print("Input data_index: " + str(i))

i = 0
while i < 5:
    threading.Thread(target=LongOperation, args=(i,)).start()
    i = i + 1

Output:

Spinning up a thread with this ID: <Thread(Thread-1, started 123145548488704)>
Finishing up thread ID: 123145548488704
Spinning up a thread with this ID: <Thread(Thread-2, started 123145552695296)>
Finishing up thread ID: 123145552695296Input data_index: 0

Input data_index: 1
Spinning up a thread with this ID: <Thread(Thread-3, started 123145548488704)>
Finishing up thread ID: 123145548488704
Input data_index: 2
Spinning up a thread with this ID: <Thread(Thread-4, started 123145552695296)>
Finishing up thread ID: 123145552695296
Input data_index: 3

Spinning up a thread with this ID: <Thread(Thread-5, started 123145556901888)>
Finishing up thread ID: 123145556901888
Input data_index: 4

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM