多进程(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的多线程并不能利用多核.所以要想利用多核,还是好好用多进程吧!

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

时间: 2024-10-09 23:47:15

多进程(mutiprocessing)与多线程(Threading)之多线程的相关文章

多进程 multiprocessing 多线程Threading 线程池和进程池concurrent.futures

multiprocessing.procsess 定义一个函数 def func():pass 在if __name__=="__main__":中实例化 p = process(target=子进程要执行的函数,args(函数的参数且必须以元组的方式传参)) p.start() 开启子进程 p.join() 感知子进程的结束,主进程等待子进程执行完后才退出 p.terminate() 结束一个子进程 p.is_alive() 查看某个进程是否还在运行 属性 p.name p.pid

Python的多线程threading和多进程multiprocessing

python中的多线程就是在一个进程中存在着多个线程,在线程中,所有的线程都是共享资源的,线程之间的数据通信很简单.但是python仅支持一个线程的运行,因为python中存在一个全局解释器锁GIL(global interpreter lock),正是这个锁能保证同一时刻只有一个线程在运行,所以多线程依旧像是单线程的运行. GIL无疑就是一把对多线程有影响的全局锁,解决它对多线程的影响,不单单是释放GIL这么简单.GIL使得对象模型都是可以并发访问.GIL全局解释器锁解决多线程之间数据完整性和

Python 多线程threading模块

首先,我们在了解多线程时需要理解的就是什么是多线程,按照官方的解释就是:多线程(英语:multithreading),是指从软件或者硬件上实现多个线程并发执行的技术. 在我自学到这里的时候,通过会在想进程和线程到底是有什么区别,我的理解就是: 进程就是一个应用程序在处理机上的一次执行过程,它是一个动态的概念,而线程是进程中的一部分,一个进程可以包含多个线程. 下面就以简单的例子来加强我们对python 线程的理解. 默认情况下,我们在没有启动线程的时候,可以看一下程序总的运行时间,应该是每个函数

【python标准库学习】thread,threading(二)多线程同步

继上一篇介绍了python的多线程和基本用法.也说到了python中多线程中的同步锁,这篇就来看看python中的多线程同步问题. 有时候很多个线程同时对一个资源进行修改,这个时候就容易发生错误,看看这个最简单的程序: import thread, time count = 0 def addCount(): global count for i in range(100000): count += 1 for i in range(10): thread.start_new_thread(ad

【python标准库学习】thread,threading(一)多线程的介绍和使用

在单个程序中我们经常用多线程来处理不同的工作,尤其是有的工作需要等,那么我们会新建一个线程去等然后执行某些操作,当做完事后线程退出被回收.当一个程序运行时,就会有一个进程被系统所创建,同时也会有一个线程运行,这个线程就是主线程main,在主线程中所创建的新的线程都是子线程,子线程通常都是做一些辅助的事.python中提供了thread和threading两个模块来支持多线程. python中使用线程有两种方式,第一种是用thread模块的start_new_thread函数,另一种是用threa

多线程threading

#-*-coding:utf-8-*-import threading #创建多线程(thread二次封装)from time import ctime,sleepimport timedef listen(name): print ('begin listening to {name} {time}'.format(name='shabi',time=ctime()))#类似html的变量,ctime 时间转换成字符串 time.sleep(3) print ('over {time}'.fo

C#多线程学习(一) 多线程的相关概念

什么是进程?    当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源.而一个进程又是由多个线程所组成的. 什么是线程?    线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针.程序计数器等),但代码区是共享的,即不同的线程可以执行同样的函数. 什么是多线程?    多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并行执行的线程来完成各自的任务. 多线程的好处:    可以提

C#多线程学习(一) 多线程的相关概念(转)

什么是进程?当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源.而一个进程又是由多个线程所组成的. 什么是线程?线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针.程序计数器等),但代码区是共享的,即不同的线程可以执行同样的函数. 什么是多线程?多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并行执行的线程来完成各自的任务. 多线程的好处:可以提高CPU的利用率.在多线程程序中

多线程系列(1)多线程基础和Thread

因为现项目中有用到多线程和并发的知识,所以打算近期补习一下多线程相关的内容.第一篇文章从最基础的开始,就是如何开启一个线程,如何启动线程和阻塞线程等,这篇文章分以下几点进行总结. 多线程初印象 多线程的使用场景 线程的启动,挂起和终止 一个简单的多线程实例 多线程初印象 首先通过一张图来了解一下进程Process,应用程序域AppDomain和线程Thread之间的关系. 从图中可以总结出以下几点: 一个进程Process可能包含多个应用程序域,也包含多个线程,线程也可以穿梭于多个应用程序域当中