为什么有人说python的多线程是鸡肋呢?

为什么Python的多任务被批评为“不请自来”?此问题是由内部全局解释器锁(GIL)引起的。
GIL的存在意味着在任何给定时间,只有一个Python解释器正在执行Python字节码。
这意味着虽然Python支持多线程,但多线程的性能提升在CPU密集型任务中往往并不明显。
当我们关注多任务Python时,重点往往是IO操作。
这类工作大部分时间必须等待I/O操作完成,例如绘图过程。
在这些情况下,多个线程可以同时执行,从而提高整体效率,因为等待I/O操作的线程可以使用其他线程来连续运行。
然而,对于CPU密集型任务,多线程的性能不如单线程,因为线程之间的切换会带来额外的开销。
因此,对于CPU密集型任务,建议使用Python多处理库。
它依赖于多个进程汇聚的多个工具,避免了GIL的影响,从而在CPU密集型任务中提供更好的性能。
值得注意的是,在使用多处理时,变量共享通常需要使用muria库。
对于不确定代码类型(CPU密集型还是IO密集型)的场景,可以尝试使用phantommultiprocessing子模块,它实现了基于多线程的多处理API。
通过比较使用多处理和多线程实现并发的性能,您可以选择更高效的解决方案。
最后值得一提的是,并发Python库提供了更简单的API,包括ThreadPoolExecutor和ProcessPoolExecutor,在某些情况下可以提供更方便的并发执行。

Python多线程编程之线程结束

线程管理包括创建线程、启动线程、休眠线程、等待线程完成和停止线程。
创建线程、启动线程、休眠线程已经提到过,这里不再重复。

1等待线程结束

等待线程结束使用join()方法当前线程调用线程t1的join()方法时,会阻塞当前进程并等待。
线程t1结束。
如果线程t1终止或超时到期,则当前线程返回活动状态并继续执行。
join()方法的语法如下:

join(timeout=None)

timeout参数用于定义超时时间,单位为s。
如果不设置超时,可以无限等待

当一个线程依赖于另一个线程的执行结果时,可以调用另一个线程的join()方法并等待其完成

示例:

importthreadingimporttimeshared_value=0defthread_body():globalshared_valueprint('ThreadA正在启动...')for_inrange(5):print('ThreadA正在运行...')share_value+=1time.sleep(1)print('ThreadA正在运行...')defmain():print("主线程启动...")t1=threading.Thread(target=thread_body,name='ThreadA')t1.start()print('主线程是阻塞...')t1.join()print(f'value={shared_value}')print('主线程继续执行...')

结果:

主线程正在启​​动...ThreadA正在启动...主线程被阻止停止...ThreadA正在运行...ThreadA正在运行...ThreadA正在运行...ThreadA正在运行。
执行.....ThreadA结束...value=5主线程继续执行...

这里定义了一个共享变量shared_value,在body中修改该变量线程的。
在main函数中调用t1的join()方法会导致主线程阻塞,等待线程t1执行完毕后,主线程才会继续执行。
从结果来看,主线程丢失并阻塞,打印的shared_value从0变成了5

2个线程停止

对于一些复杂的业务,需要定义一个线程停止变量来判断线程停止。
比如有一个系统,采集数据,每半小时执行一次数据采集任务。
数据录入任务通常在子线程中执行,并在执行前休眠一定时间。
这个子线程在中国会无限循环。
为了停止子线程,必须定义一个线程停止变量

示例:

importthreadingimporttimeis_running=Truedefthread_body():whileis_running:print('ThreadAstart...')#数据捕获任务print('ThreadA正在运行...')time.sleep(1)print('ThreadA正在运行中...')print('整个程序执行完毕')defmain():print('主线程正在启​​动..')t1=threading.Thread(target=thread_body)t1.start()command=input('请输入关闭命令:')ifcommand=='exit':globalis_runningis_running=Falseif__name__=='__main__':main()

结果:

主线程启动.......ThreadA开始...ThreadA正在运行...请输入停止命令:exitThreadA结束...整个程序执行终止

这里定义了一个线程。
关闭变量is_running,默认值为True。
当用户通过键盘在控制台输入exit时,其值变为False,程序退出。
请注意,在输入exit后控制台,你仍然需要按回车键。

python编程的多线程为何是伪多线程?

为什么Python中的多线程称为伪多线程?这与全局解释器锁(GIL)的概念密切相关。
当Python最初设计时,开发团队假设主循环中只能运行一个线程,就像运行多个进程的单核处理器一样。
虽然Python可以同时运行多个线程,但本质上Python虚拟机(解释器)中只有一个线程运行。
GIL负责访问Python虚拟机并确保一次只有一个线程在运行。
在多线程环境下,Python的执行过程如下:1.设置GIL。
2.切换到一个线程执行。
3.跑步。
4.线程进入睡眠状态。
5.解锁GIL。
6.重复上述步骤。
具体来说,每执行100个字节码,GIL就被释放,以便其他线程有机会执行。
因此,在Python的多线程环境中,程序实际上是交替执行的,这是通过上下文切换来实现的,而不是同时执行代码。
这导致Python在处理大量并发任务时多线程性能比C或C++等语言差。
然而,Python多线程非常适合I/O密集型任务,因为I/O操作通常需要等待外部资源,而其他线程可以利用空闲时间执行其他任务。
总的来说,理解GIL的作用对于深入理解Python的多线程能力至关重要。