多进程(mutiprocessing)与多线程(Threading)之多线程

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多进程(mutiprocessing)与多线程(Threading)之多线程相关的知识,希望对你有一定的参考价值。

多线程(threading)

多线程与多进程其实大同小异,他们有很多方法从名字到功能都是一样,比如都有start(),join(),都有守护线程/进程deamon.

一个简单的栗子:

import threading
import os,time

def loop():
    for i in range(5):        
        t = threading.Thread(name=str(i))        
        t.start()
        print(thread %s is running!%t.name)
        print(thread %s exited!%t.name)
        t.join()
        

if __name__ == "__main__":
    print(thread %s is running!%threading.current_thread().name)
    T = threading.Thread(target=loop)
    T.start()
    T.join()
    print(thread %s exited%threading.current_thread().name)

output:

技术分享

由于Python的多线程并不是真正意义上充分利用多核性能的多线程,它是只是实现了单核并发(详见并发与并行),也就是说,处理多线程时,

每个线程执行一部分代码,然后执行下一个线程的代码,所以稍不留神,输出就会跟设计的初衷相左.

 

import  threading
import time

num = 0

def change(n):
    #声明全局变量num
    global num
    #进行加减n
    num = num + n
    num = num - n

def run_thread(n):
    #调用change方法100万次
    for i in range(1000000):
        change(n)

if __name__ == "__main__":
    t1 = threading.Thread(target=run_thread,args=(5,))
    t2 = threading.Thread(target=run_thread,args=(8,))
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print(num)

 

output:

第一次:

技术分享

第二次:

技术分享

第三次:

技术分享

会得出三次不同的结果,事实上,如果增大调用change的次数,结果会更显著.

原因是多线程间的变量是共享的.num在被线程t1,t2交替使用.

语句num = num + n其实分作两步:

先计算num+n的值存入临时变量

然后把临时变量赋值给num

但在多线程中,尤其是运算量大的地方,并不能保证这两步的连贯执行,因此就不能保证结果的准确性.

因此我们需要引入多线程特有的类:锁!

Lock

Lock类只有两个方法:

acquire(blocking=Truetimeout=-1)

这是一个等待锁的方法,可选参数也是我们的老朋友,堵塞与超时

release()释放锁的方法,一个函数获取了锁之后一定要释放锁,否则还在等待锁的程序望穿眼也等不到锁,成为幽灵线程.

所以,上述的代码要这样优化:

import  threading
import time

num = 0
lock = threading.Lock()
def change(n):
    #声明全局变量num
    global num
    #进行加减n
    num = num + n
    num = num - n
    

def run_thread(n):
    #调用change方法100万次
    for i in range(1000000):
        #获取锁        
        lock.acquire()
        try:
            change(n)
        finally:
            #最后必定要释放锁
            lock.release()

if __name__ == "__main__":    
    t1 = threading.Thread(target=run_thread,args=(5,))
    t2 = threading.Thread(target=run_thread,args=(8,))    
    t1.start()    
    t2.start()
    t1.join()
    t2.join()
    print(num)

这样无论怎么如何,结果都错不了了!

最后的最后,由于Python GIL(全局锁)的存在,任何Python线程执行前,线程都要获得GIL锁,然后没执行100条字节码,自动释放GIL锁,然后去执行其他的线程任务,

所以Python的多线程并不能利用多核.所以要想利用多核,还是好好用多进程吧!

文章参考了廖雪峰廖大的教程,感谢廖大!

以上是关于多进程(mutiprocessing)与多线程(Threading)之多线程的主要内容,如果未能解决你的问题,请参考以下文章

网络编程之多线程——多线程与多进程的区别

python 多线程和多进程的区别 mutiprocessing theading

基于Python的多线程与多进程

多线程与多进程介绍

python多进程与多线程使用场景

Python多线程与多进程