今天本来打算学习学习多进程的,但是由于我现在的电脑没有Linux系统,无法通过Linux系统编辑一些多进程的程序,因此我打算从多线程入手。
多线程
我们的程序一般都是多任务的,如果你没有好好的利用好,运行时就会出现卡顿,甚至程序奔溃,这是因为所以的任务都挤在同一个地方。
多任务可以由多进程完成,而多进程可以由多线程完成。由于线程是操作系统直接支持的执行单元,因此,高级语言都有内置线程,而且python下的线程是真正的posix Thread,而不是模拟的线程。(图1)
在python中的标准库提供了两个模块,一个是_thread和threading;前者是低级模块,后者是高级模块,我们就用threading模块就可以,它对_thread进行了封装。
启动一个线程就是把一个函数传入并创建thread实例,比如我们有一个输出函数(图2)
由于任何进程默认就会启动一个线程,我们把该线程称为主线程,主线程又可以启动新的线程,Python的threading模块有个current_thread()函数,它永远返回当前线程的实例。主线程实例的名字叫MainThread,子线程的名字在创建时指定,上例中我们用shuchu命名子线程。名字仅仅在打印时用来显示,完全没有其他意义,如果不起名字Python就自动给线程命名为Thread-1,Thread-2……
lock
线程锁,因为在线程中所以的变量都由所以线程共享,所以所以变量都可能被修改,这样就很容易造成混乱,这时候就需要线程锁来协助了
假如当多个线程同时执行lock.acquire()时,只有一个线程能成功地获取锁,然后继续执行代码,其他线程就要继续等待直到获得锁为止。
代码示例:
num = 0
def shuchu(n):
global num
num = num+n
num = num-nlock = threading.Lock()
def run(n):
for i in range(100000): lock.acquire() # 获取锁:try: shuchu(n) #修改数据 finally: lock.release() #释放锁:run()
获得锁的线程用完后一定要用lock.release来释放锁,否则那些苦苦等待锁的线程将永远等待下去,成为死线程。所以我们用try…finally来确保锁一定会被释放。
锁的好处就是确保了某段关键代码只能由一个线程从头到尾完整地执行,坏处当然也很多,首先是阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了。其次,由于可以存在多个锁,不同的线程持有不同的锁,并试图获取对方持有的锁时,可能会造成死锁,导致多个线程全部挂起,既不能执行,也无法结束,只能靠操作系统强制终止。
多线程编程,模型复杂,容易发生冲突,必须用锁加以隔离,同时,又要小心死锁的发生。