python多线程

来源:互联网 发布:西安鼓楼网络售票 编辑:程序博客网 时间:2024/05/17 13:07

**

什么是线程?

**
线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。(维基百科)
上面的解释很抽象吧,我再解释一下。当一个程序启动时,就会产生一个进程或者多个进程,当一个进程产生,同时也会产生一个进程,这个进程就是主进程。而主进程还会产生子进程,这些子进程是可以同时进行的。
例如,有两个这样的程序:

def a():    print('第一个函数')def b():    print('第二个函数')a()b()

上面的程序先执行函数a(),再执行函数b()。如果要用到进程的话,函数a()和函数b()可以同时进行。

**

python中的进程

**
python提供了threading模块进行进程的调控。我们把上面的那段程序改写成多进程的:

import threadingdef a():    print('第一个函数\n')def b():    print('第二个函数\n')th1=threading.Thread(target=a)th2=threading.Thread(target=b)th1.start()th2.start()

运行结果:

>>> 第一个函数第二个函数

也有可能是:

>>> 第二个函数第一个函数

为什么会出现这种状况,为什么呢?因为函数a()和函数b()是同时启动的,执行时间差不多,所以有可能是a()先执行完,也有可能是b()先执行完。然后,我们再看看进程的形式th1=threading.Thread(target=a),其中th1是子进程的名字,target锁定函数,如果函数有参数怎么办?要写成threading.Thread(target=a,args=(x,x))这种形式。当把函数写进进程后,就要启动,th1.start()

这段程序不太能体现出线程的优点,我们再写一段程序:

import threading,timedef a():    print('a begin!')    print('a is running.........')    time.sleep(2)    print('a end!')def b():    print('b begin!')    print('b is running.........')    time.sleep(2)    print('b end!')_time=time.time()a()b()print('共耗时%f秒'%(time.time()-_time))

运行结果:

a begin!a is running.........a end!b begin!b is running.........b end!共耗时4.058232

上面的代码没有写成进程,所以共耗时4秒。我们把它写成进程:

import threading,timedef a():    print('a begin!')    print('a is running.........')    time.sleep(2)    print('a end!')def b():    print('b begin!')    print('b is running.........')    time.sleep(2)    print('b end!')_time=time.time()_a=threading.Thread(target=a)_b=threading.Thread(target=b)_a.start()_b.start()_b.join()_b.join()print('共耗时%f秒'%(time.time()-_time))

运行结果:

a begin!b begin!a is running.........b is running.........a end!b end!共耗时2.073119

从上面的结果可以看出耗时2秒,节省了一半时间。join()函数是起到阻塞的作用,详细用法见我的博客:python多线程中join和setDaemon的用法。

**

线程中的互斥

**
先写个实例程序:

import threading,timenum=0def a(n):    global num    num=num+n    num=num-ndef change(n):    for i in range(100000):        a(n)t1=threading.Thread(target=change,args=(5,))t2=threading.Thread(target=change,args=(8,))t1.start()t2.start()t1.join()t2.join()print(num)

在上面代码中,执行函数change(),根据我们的算法,无论函数的参数是多少,执行多少次,num的结果应该始终是零。但是运行结果如下:

13

或者:

-2

这是为什么呢?num是全局变量,在同一进程下的线程之间的变量是共享的,所以,在t1和t2这两个进程中都会对num进行操作。当执行到线程t1中num=num+你,应该接着执行t1进程中的num=num-1,但是进程都是同时进行的,所以会对num进行线程t2中的操作,num因此会出现其他值。为了避免多个进程同时对一个变量或者文件操作,python引进了互斥锁:当一个进程对一个变量或一个文件进行操作时,会禁止其他进程对此变量或者文件进行操作。我们可以将上面的代码改写如下:

import threading,timenum=0mylock=threading.Lock()def a(n):    global num    mylock.acquire()    num=num+n    num=num-n    mylock.release()def change(n):    for i in range(100000):        a(n)t1=threading.Thread(target=change,args=(5,))t2=threading.Thread(target=change,args=(8,))t1.start()t2.start()t1.join()t2.join()print(num)

这样执行的结果始终是0。此外,只要加锁就一定要解锁,否则会形成死锁,就是其他进程始终不能对变量进行操作。加锁的位置只要能够将变量包住就行,例如将锁加在如下位置也可以:

def change(n):    for i in range(100000):        mylock.acquire()        a(n)        mylock.release()

**

python中多线程的本质

**
在python中的多线程其实并不能真正利用多核CPU的优势,这是因为在python中有一个GIL(Global Interpreter Lock)。Python在执行多线程程序时,其中一个线程在执行前先获GIL,这样其他的线程就不能执行。当第一个线程执行了若干行代码后再释放GIL,由另外一个线程获得GIL并执行。由此可见,早Python中多线程必不能有效的利用多核CPU的优势。因此为了个好的有效利用多核CPU,所以我们可以创建多个多线程的进程。

0 0
原创粉丝点击