python学习笔记(32)多线程&多进程

一、多线程&多进程

  对于操作系统来说,一个任务就是一个进程。比如我在电脑上打开视频看电视,再启动QQ,这样打开视频和启动QQ就是两个进程了 。进程是多个资源的集合

  每个进程中可以做很多事情,比如我打开QQ,可以与A打字聊天,同时还可以与B视频,接收C的文件,一个进程中可以有很多线程来干活,这样一个QQ需要运行多个子任务,我们把这些子任务叫做 线程(thread)

 

  每个进程中至少有一个线程在干活,比如我打开QQ,即使不做任何操作,还是保留了一个QQ窗口,这就是主线程,子线程会等着主线程来调

 

  我们在做事情的时候,一个人做是比较慢的,如果多个人一起来做的话,就比较快了,程序也是一样的,我们想运行的速度快一点的话,就得使用多进程,或者多线程,在python里面,多线程被很多人诟病,为什么呢,因为Python的解释器使用了GIL的一个叫全局解释器锁,它不能利用多核CPU,

  只能运行在一个cpu上面,但是你在运行程序的时候,看起来好像还是在一起运行的,是因为操作系统轮流让各个任务交替执行,任务1执行0.01秒,切换到任务2,任务2执行0.01秒,再切换到任务3,执行0.01秒……这样反复执行下去。

  表面上看,每个任务都是交替执行的,但是,由于CPU的执行速度实在是太快了,  我们感觉就像所有任务都在同时执行一样。这个叫做上下文切换。  

  

二、python中通过threading模块来实现多线程

  简单启动线程的例子

import threading
    import time
    def sayhi(num): #定义每个线程要运行的函数
     
        print("running on number:%s" %num)
     
        time.sleep(3)
     
    if __name__ == '__main__':
        t1 = threading.Thread(target=sayhi,args=(1,)) #生成一个线程实例
        t2 = threading.Thread(target=sayhi,args=(2,)) #生成另一个线程实例
        t1.start() #启动线程
        t2.start() #启动另一个线程

  

  

主线程,也就是程序一开始运行的时候,最初的那个线程
子线程,通过thread类实例化的线程,都是子线程
如果加了线程等待,主线程等待子线程,执行结束后,主线程再去做别的操作。否则主线程在启动子线程后,不会等待子线程结束,而是继续走主线程代码

下面举例说明两种线程等待的方式
import threading
import time
def insert_db():
    time.sleep(3)
    print('insert_db over')

#串形的方式,非多线程
# start_time = time.time()
# for i in range(3):
#     insert_db()
# end_time = time.time()
# print('串行的执行的时间',end_time - start_time )

threads = []
start_time2 = time.time()

#1、第一种方式,麻烦一点
# for i in range(3):
#     t = threading.Thread(target=insert_db)#有入参时,需要加args=()或者args=[]来传递参数
#     t.start()
#     threads.append(t)
#
# for t in threads:
#     t.join()#使用join实现主线程等待子线程结束

#2、第二种方式,思路是判断当前存活的线程个数
for i in range(3):
    t = threading.Thread(target=insert_db)
    t.start()
#当线程数为1,即子线程结束,代码才往下走,否则在死循环中
while threading.activeCount()!=1:#活着的线程数
    pass

end_time2 = time.time()
print('多线程执行的时间',end_time2 - start_time2)

  

守护线程:当主线程结束后,守护线程会自动结束。就比如秦始皇死后,所有为他建造皇陵的人全部都要去陪葬。那么秦始皇就是主线程,其他陪葬的都是子线程。

以一个视频聊天为例,关闭QQ后,所有的子线程会停止
#守护线程,一但主线程死掉,那么守护线程不管有没有执行完成,全都结束
import threading
import time
def talk(name):
    print('正在和%s聊天'%name)
    time.sleep(200)

def shipin(name):
    print('正在和%s视频'%name)
    time.sleep(300)

print("qq主窗口")
t1 = threading.Thread(target=talk,args=['刘小燕'])
t1.setDaemon(True) #设置线程为守护线程
t1.start()

t2 = threading.Thread(target=shipin,args=['蔡明昌'])
t2.setDaemon(True) #设置线程为守护线程
t2.start()

time.sleep(5)

print('结束。。。')

  

线程锁: 

  经常出现在数据库操作时,如果多线程同时操作一个数据库操作时,由于线程有快慢先后的区别,原来的数据处理完可能会出错。那么在一个线程来的时候,加上一把锁,只有等这个线程干活结束后,再把锁打开,下一个线程再去操作数据干活,这样数据就不会乱套了

  

import threading
count = 0
lock = threading.Lock()#申请一把锁
def test():
    global count
    print(threading.current_thread())
    '''第一个加锁方式,不解锁后出现线程死锁'''
    # lock.acquire()#加锁
    # count+=1
    # lock.release()#解锁
    '''第二种加锁方式,会自动解锁'''
    with lock:
        count+=1

for i in  range(3):
    t = threading.Thread(target=test)
    t.start()

  

  






上一篇:线程 1.线程


下一篇:Python语言之并发编程