time.sleep与全局解释器锁
Cpython解释器中有全局解释器锁(GIL),一次只允许使用一个线程执行Python字节码,因此一个python进程通常不能同时使用多个CPU核心。
然而标准库中,所有C语言编写I/O操作的函数,等待操作系统返回结果时,都会释放GIL。
比如像time.sleep()函数:作用是在一段时间不会返回或者执行其他代码。
一段时间结束后,time.sleep也会释放GIL,从而允许其他线程进行。
使用Python处理CPU密集型工作时,应该试试PyPy,futures模块。
或者使用分布式计算引擎Apache Spark,支持把Python对象当做数据。
多线程
import time,datetime startTime=datetime.datetime(2029,10,31,0,0,0) while datetime.datetime.now() < startTime: time.sleep(1) print('Happy Halloween 2029')
这段代码指定2029年10月31日作为开始时间,不断地调用time,sleep(1),在2029年10月31日没到那天,程序将一直“沉睡”。
这是因为前面提到的全局解释器锁的原因。Python程序在默认的情况下,只有一个执行线程。
单线程程序的执行就像一个”逐行”读书的手指,而多线程程序的执行可以为有多个“逐行”读书的手指。
为了不必让所有代码等待,我们可以在原来的线程外,在创建一个线程,这个单独的线程可以执行延迟或安排的代码。
为此我们可以这样做:
import threading,time print('程序启动.') def takeANap(): time.sleep(5) print('Wake up!') threadObj=threading.Thread(target=takeANap) threadObj.start() print('程序结束.')
输出结果会是这样
程序启动.
程序结束.
Wake up!
为什么最后两个顺序是这样的呢?
这是因为当程序运行到start()函数时,takeANap函数已经被放入一个新的执行线程中。这个时候相当于
一个手指即将执行:print('程序结束.'),另一个手指已经在takeANap函数入口处,这个时候主线程会打印出程序结束内容,新线程会在小睡后打印Wake up!
通常程序会在最后一行代码执行后终止,对于此例则有两个线程。在程序的所有执行线程终止前,程序不会终止。所以即使主线程已经完成使命,新线程仍会sleep。
多线程会遇到的问题:并发问题
如果这些线程同时读写变量,会导致互相干扰,最终会发生并发问题。
有关线程的初学者教程更多见:
http://nostarch.com/automatestuff/