Python 相同的回调,多个线程

Python 相同的回调,多个线程,python,multithreading,Python,Multithreading,如果我创建多个线程并向所有线程传递相同的精确回调,那么这些线程是否会同时执行相同的内存块(相同的函数/回调)?线程回调是通过值传递还是通过引用传递?这是否与语言有关?由于全局解释器锁与C#等语言相比,这在Python中如何工作 下面的代码显示正在打印的不同线程ID,但函数位置如何?是否有LongOperation的副本,或者每次运行代码时每个线程都访问相同的内存位置 python中的示例代码: def LongOperation(): print( "Spinning up a thre

如果我创建多个线程并向所有线程传递相同的精确回调,那么这些线程是否会同时执行相同的内存块(相同的函数/回调)?线程回调是通过值传递还是通过引用传递?这是否与语言有关?由于全局解释器锁与C#等语言相比,这在Python中如何工作

下面的代码显示正在打印的不同线程ID,但函数位置如何?是否有LongOperation的副本,或者每次运行代码时每个线程都访问相同的内存位置

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
def LongOperation():
打印(“旋转具有此ID的线程:+str(threading.get_ident()))
打印(“整理线程ID:+str(threading.get_ident()))
i=0
当我<10时:
threading.Thread(target=LongOperation).start()
i=i+1

感谢阅读。

函数被编译成代码对象
LongOperation
是引用这些代码块之一的变量。每次调用
LongOperation
时,python都会创建一个框架对象,该对象将保存该调用特有的局部变量。尽管框架对象将被视为“通过引用调用”,因为每个调用都会创建一个唯一的框架,但没有其他函数会引用它。例外情况是,如果函数具有
产量
。然后您就有了一个可以传递给许多其他函数的生成器

在您的例子中,每个线程访问代码的相同函数对象,但访问数据的单独帧对象。这与C非常相似,在C中,许多调用者将获得相同的代码,但数据的堆栈帧不同

CPython仅在线程获取GIL时执行字节码。它会定期释放GIL,让线程交错,但一次只能执行一个线程。Python扩展(无论是在Python的stdlib中,例如正则表达式,还是在外部,例如numpy)都可以自由地发布GIL。这不是必需的,当需要释放GIL时,这是一种个人意见。CPython在执行阻塞操作(如读取文件)时也会释放GIL

如果您的纯python不使用GIL发布的扩展,也不执行I/O,那么多线程并不比按顺序执行快。但是,如果您的代码做了这些事情,多线程可能会有所帮助

Python的异步支持非常适合处理文件系统或网络访问等阻塞问题。它自然可以扩展到完全向程序提交1个cpu,而不需要在更传统的程序中管理多个线程


如果您使用释放GIL的软件包进行大型数值处理,多线程又会变得有趣,因为您的程序可以使用多个CPU。

函数被编译成代码对象
LongOperation
是引用这些代码块之一的变量。每次调用
LongOperation
时,python都会创建一个框架对象,该对象将保存该调用特有的局部变量。尽管框架对象将被视为“通过引用调用”,因为每个调用都会创建一个唯一的框架,但没有其他函数会引用它。例外情况是,如果函数具有
产量
。然后您就有了一个可以传递给许多其他函数的生成器

在您的例子中,每个线程访问代码的相同函数对象,但访问数据的单独帧对象。这与C非常相似,在C中,许多调用者将获得相同的代码,但数据的堆栈帧不同

CPython仅在线程获取GIL时执行字节码。它会定期释放GIL,让线程交错,但一次只能执行一个线程。Python扩展(无论是在Python的stdlib中,例如正则表达式,还是在外部,例如numpy)都可以自由地发布GIL。这不是必需的,当需要释放GIL时,这是一种个人意见。CPython在执行阻塞操作(如读取文件)时也会释放GIL

如果您的纯python不使用GIL发布的扩展,也不执行I/O,那么多线程并不比按顺序执行快。但是,如果您的代码做了这些事情,多线程可能会有所帮助

Python的异步支持非常适合处理文件系统或网络访问等阻塞问题。它自然可以扩展到完全向程序提交1个cpu,而不需要在更传统的程序中管理多个线程

如果您使用释放GIL的软件包进行大型数值处理,多线程又会变得有趣,因为您的程序可以使用多个CPU。

  • 如果我创建多个线程并向所有线程传递相同的精确回调,那么这些线程是否会同时执行相同的内存块(相同的函数/回调)

    是的,它们使用相同的程序代码

  • 线程回调是通过值传递还是通过引用传递

    每个线程都可以有其局部变量

  • 这是否与语言有关

    不确定,但我想是的

  • 由于全局解释器锁与C#等语言相比,这在Python中如何工作

    我不认为它与GIL有关,您仍然可以使用多线程Python进行高IO(而不是CPU)工作

对于您的代码,我对其进行了测试:

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
导入线程
导入时间
操作(一):
打印(“旋转具有此ID的线程:+str(threading.currentThread()))
打印(“整理线程ID:+str(threading.currentThread().ident))
打印(“输入数据索引:+str(i))
i=0
当我<5时:
threading.Thread(target=LongOperation,args=(i,).start()
i=i+1
输出:

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
旋转具有此ID的线程:
菲尼希