上一篇博客介绍了Python并发编程的基本知识,感兴趣的可以到专利找到上一篇文章,本文主要介绍如何开启多线程,以及多线程在提升效率的同时会存在哪些问题
Python通过标准库的 threading 模块来管理线程。这个模块提供了很多不错的特性,让线程变得无比简单,打开threading.py文件,可以到如下类或者方法

线程模块常用的主要组件有,Thread、Event、Lock、RLock、Semaphore、Timer等等,他们可以用来开启线程、保证线程间的安全、线程间的通信等等
使用线程最简单的一个方法是,用一个目标函数实例化一个Thread然后调用 start() 方法启动它。示例如下
import threading
def function(i):
    print ("function called by thread %i\n" % i)
    return
threads = []
for i in range(5):
    t = threading.Thread(target=function , args=(i, ))
    threads.append(t)
    t.start()
    t.join()上述代码就可以开启5个线程执行function函数
Thread()参数解释如下
- 
group: 一般设置为None,这是为以后的一些特性预留的
- 
target: 当线程启动的时候要执行的函数
- 
name: 线程的名字,默认会分配一个唯一名字Thread-N
- 
args: 传递给target的参数,要使用tuple类型
- 
kwargs: 同上,使用字典类型dict
Thread类定义的常用方法如下
- 
start(): 启动线程,并执行run()方法。
- 
run(): 线程启动后执行的方法,可以在子类中重写。
- 
join([timeout]): 等待线程结束,可选参数timeout指定最长等待时间。
- 
is_alive(): 判断线程是否仍然存活。
- 
name: 线程名称的属性,可以在实例化时指定或修改。
- 
setDaemon(daemonic): 设置线程是否为守护线程,默认为 False。守护线程会在主线程结束时自动退出。
- 
getName(): 获取线程名称。
- 
setName(name): 设置线程名称。
多个线程操作同一个资源,并且至少有一个可以改变数据,又没有同步机制的条件下,就会产生竞争条件,可能会导致执行无效代码、bug、或异常行为。
这时候可以用Lock来保持线程同步,例如下列代码,在下面的代码中,我们有两个函数: increment() 和 decrement() 。第一个函数对共享资源执行加1的操作,另一个函数执行减1.两个函数分别使用线程封装。除此之外,每一个函数都有一个循环重复执行操作。我们想要保证,通过对共享资源的管理,执行结果是共享资源最后等于初始值0.
# -*- coding: utf-8 -*-
import threading
shared_resource_with_lock = 0
shared_resource_with_no_lock = 0
COUNT = 10000000
shared_resource_lock = threading.Lock()
# 有锁的情况
def increment_with_lock():
    global shared_resource_with_lock
    for i in range(COUNT):
        shared_resource_lock.acquire()
        shared_resource_with_lock += 1
        shared_resource_lock.release()
def decrement_with_lock():
    global shared_resource_with_lock
    for i in range(COUNT):
        shared_resource_lock.acquire()
        shared_resource_with_lock -= 1
        shared_resource_lock.release()
# 没有锁的情况
def increment_without_lock():
    global shared_resource_with_no_lock
    for i in range(COUNT):
        shared_resource_with_no_lock += 1
def decrement_without_lock():
    global shared_resource_with_no_lock
    for i in range(COUNT):
        shared_resource_with_no_lock -= 1
if __name__ == "__main__":
    t1 = threading.Thread(target=increment_with_lock)
    t2 = threading.Thread(target=decrement_with_lock)
    t3 = threading.Thread(target=increment_without_lock)
    t4 = threading.Thread(target=decrement_without_lock)
    t1.start()
    t2.start()
    t3.start()
    t4.start()
    t1.join()
    t2.join()
    t3.join()
    t4.join()
    print ("the value of shared variable with lock management is %s" % shared_resource_with_lock)
    print ("the value of shared variable with race condition is %s" % shared_resource_with_no_lock)输出
the value of shared variable with lock management is 0
the value of shared variable with race condition is -242686可以看到未加锁的程序出现了错误,如果你运行了示例代码没有出错,可以把COUNT值调大试试
但加锁有什么缺点呢,第一会消耗资源,第二如果程序中有多个锁存在,可能会造成死锁,导致程序一直卡住,我们设有两个并发的线程( 线程A 和 线程B ),需要 资源1 和 资源2 .假设 线程A 需要 资源1 , 线程B 需要 资源2 .在这种情况下,两个线程都使用各自的锁,目前为止没有冲突。现在假设,在双方释放锁之前, 线程A 需要 资源2 的锁, 线程B 需要 资源1 的锁,没有资源线程不会继续执行。这就出现了死锁问题。
下篇文章介绍如何解决多线程的死锁问题