python之多线程一

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wzg_inspur/article/details/86213165

这几天学习了一下python的多线程,将具体的知识点整理如下:

线程的定义:就是一堆指令集的执行

线程设计到的模块:threading 模块

线程的用法:

import threading

def fun(n):
    pass
t1 = threading.Thread(target=fun,args=(1,))
t1.start()

通过threading.Thread()来创建线程对象,target参数指向线程执行的函数,args代表函数需要的参数,参数用元祖的形式表示。

现在模范一个同时看书和听音乐的场景,代码如下:

import threading
import time

def music(func):
    for i in range(0,2):
        print('start play music %s  %s'%(func,time.ctime()))
        time.sleep(2)
        print('end play music %s'% time.ctime())

def movie(func):
    for i in range(0,2):
        print('start play movie %s  %s'%(func,time.ctime()))
        time.sleep(3)
        print('end play movie %s'% time.ctime())


threads=[]
t1 = threading.Thread(target=music,args=('听心',))
threads.append(t1)
t2 = threading.Thread(target=movie,args=('海王',))
threads.append(t2)

if __name__ == '__main__':
    #t1.setDaemon(True)
    t1.setDaemon(True)
    for t in threads:
        t.start()
    print('music and movie has finished %s'% time.ctime())

在这里我们定义了一个music和movie函数,开启两个线程执行这两个任务,这样主线程和两个子线程将会同时执行。执行结果如下:

start play music 听心  Thu Jan 10 09:19:25 2019     子线程
start play movie 海王  Thu Jan 10 09:19:25 2019     子线程
music and movie has finished Thu Jan 10 09:19:25 2019 主线程
end play music Thu Jan 10 09:19:27 2019   子线程
start play music 听心  Thu Jan 10 09:19:27 2019   子线程
end play movie Thu Jan 10 09:19:28 2019   子线程
start play movie 海王  Thu Jan 10 09:19:28 2019   子线程
end play music Thu Jan 10 09:19:29 2019   子线程
end play movie Thu Jan 10 09:19:31 2019   子线程

执行过程如下:两个线程同时启动,音乐线程先抢到cpu资源,执行,到执行sleep(2)函数时,cpu资源就被释放掉了,进而执行电影线程,之后主线程继续执行。后面的过程跟上面的差不多。就不分析了。

这里sleep()函数就相当于是一个IO密集型的任务,针对IO密集型的任务并发执行效率会提升,那如果针对计算密集型任务,在python中多线程就没有办法解决了。因为cpython解释器中的GIL(全局解释器锁)原因,因为GIL只能允许同一时刻只能进入一个线程进行解释器执行。

如果想要主线程最后执行,就需要通过join()函数来进行解决,join函数的作用为等待这个线程执行完毕,再去执行其他的线程。

if __name__ == '__main__':
    #t1.setDaemon(True)
    t1.setDaemon(True)
    for t in threads:
        t.start()
    t.join() #这里的t指向for循环最后一次的线程即t2  总计消耗6s
    print('music and movie has finished %s'% time.ctime())

执行结果如下:

start play music 听心  Thu Jan 10 09:30:45 2019
start play movie 海王  Thu Jan 10 09:30:45 2019
end play music Thu Jan 10 09:30:47 2019
start play music 听心  Thu Jan 10 09:30:47 2019
end play movie Thu Jan 10 09:30:48 2019
start play movie 海王  Thu Jan 10 09:30:48 2019
end play music Thu Jan 10 09:30:49 2019
end play movie Thu Jan 10 09:30:51 2019
music and movie has finished Thu Jan 10 09:30:51 2019

从结果来看,主线程是等待线程执行完毕后才执行的。证明join的作用是生效的。

如果想让线程在后台执行,可以将线程设置为守护线程,通过setDaemon函数来进行设置

if __name__ == '__main__':
    #t1.setDaemon(True)
    t1.setDaemon(True)
    for t in threads:
        t.setDaemon(True) #为线程设置为守护线程,后台自动执行
        t.start()
    print('music and movie has finished %s'% time.ctime())

执行结果:

start play music 听心  Thu Jan 10 09:37:45 2019
start play movie 海王  Thu Jan 10 09:37:45 2019
music and movie has finished Thu Jan 10 09:37:45 2019

从结果看线程都执行完毕了,其实设置为守护进程后,都去后台执行了。

一般线程都采用继承式调用,通过自己封装类并继承threading.Thread类,代码结构如下:

import threading
import time

class myThread(threading.Thread):

    def __init__(self,num):
        threading.Thread.__init__(self)#调用父类的构造函数方法
        self.num = num

    #函数重载父类的run函数
    def run(self):
        print('the number is %s' % self.num)
        time.sleep(2)

if __name__ == '__main__':
    t1 = myThread(1)
    t2 = myThread(2)
    t1.start()
    t2.start()

多个线程同时对同一个数据进行操作时,可能会导致数据错乱,这是因为没有加入同步锁的原因。

import  threading
import time

def addNum():
    global num
    #num -= 1
    #r.acquire()
    temp=num
    time.sleep(0.00000002)
    num = temp-1
    #r.release()

num = 100
threadlist=[]

#r = threading.Lock()
for i in range(100):
    t = threading.Thread(target=addNum)
    t.start()
    threadlist.append(t)
for i in threadlist:#等待所有线程执行结束
    t.join()

print('final num %s'% num)

执行代码结果为:final num 99  这就是因为没有加入同步锁导致的。

加入同步锁后:

import  threading
import time

def addNum():
    global num
    #num -= 1
    r.acquire()
    temp=num
    time.sleep(0.00000002)
    num = temp-1
    r.release()


num = 100
threadlist=[]

r = threading.Lock()
for i in range(100):
    t = threading.Thread(target=addNum)
    t.start()
    threadlist.append(t)
for i in threadlist:#等待所有线程执行结束
    t.join()

print('final num %s'% num)

加入同步锁后,执行结果final num 0 ,因为加入同步锁后,线程不会释放,只有释放锁后,其他线程才会共同竞争资源。

如果多个线程相互等待锁的释放,就会造成死锁,而解决死锁的办法就是加入递归锁,递归锁内部有一个计数器,计数器为0时,锁自动释放。

class mythread(threading.Thread):

    def doA(self):
        lock.acquire()
        print(self.name,'getLockA',time.ctime())
        time.sleep(2)
        lock.acquire()
        print(self.name, 'getLockB', time.ctime())
        lock.release()
        lock.release()

    def doB(self):
        #time.sleep(3)
        lock.acquire()
        print(self.name,'getLockB',time.ctime())
        time.sleep(2)
        lock.acquire()
        print(self.name, 'getLockA', time.ctime())
        lock.release()
        lock.release()

    def run(self):
        self.doA()
        self.doB()


# lockA = threading.Lock()
# lockB = threading.Lock()
lock = threading.RLock() #递归锁 可以重复使用
threadlist = []
for i in range(5):
    threadlist.append(mythread())
for t in threadlist:
    t.start()

for t in threadlist:
    t.join()

通过这样方式,就不会出现死锁了。

展开阅读全文

没有更多推荐了,返回首页