python多线程

**

什么是线程?

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

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

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

a()
b()

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

**

python中的进程

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

import threading

def 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,time

def 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,time

def 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,time

num=0

def a(n):
    global num
    num=num+n
    num=num-n

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)

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

13

或者:

-2

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

import threading,time

num=0
mylock=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,所以我们可以创建多个多线程的进程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值