python学习笔记之线程间通信

15 篇文章 1 订阅

1.关于python多线程模块

我们知道线程是任务最小的执行单元,Python的标准库提供了两个模块:_thread和threading,_thread是低级模块,threading是高级模块,对_thread进行了封装。绝大多数情况下,只需要使用threading模块就好。

2.使用threading模块创建线程

相关资料: https://www.cnblogs.com/hiwuchong/p/8673183.html

语法如下:

Thread([group [, target [,name [, args [, kwargs]]]]])

group:值为None,为后续版本保留

target: 表示一个可调用对象,线程启动时,run()方法调用此对象,默认值为None,表示不调用任何对象

name:表示当前线程名称,默认创建一个名为"Thread-N"格式的唯一名称

args:表示传递给target()函数的参数元组。

kwargs:表示传递给target()参数的参数字典

ps:

*args用来将参数打包成tuple给函数体调用,如fun(1)

**kwargs打包关键字参数成dict给函数体调用,如fun(a=2),区别详请见:https://www.cnblogs.com/yunguoxiaoqiao/p/7626992.html

Thread类和Process进程类方法基本相同。

实例如下

# _*_ coding: UTF-8 _*_

import threading,time

def process():
    for i in range(3):
        time.sleep(1)
        # 输出线程名字
        print('thread name is %s' % threading.current_thread().name)

if __name__ == '__main__':
    print('主线程开始:%s'%threading.current_thread().name)
    threads = [threading.Thread(target=process) for i in range(4)] #创建4个线程
    for t in threads:  # 开启线程
        t.start()
    #print(threading.enumerate())  #获得当前所有线程
    for i in threads:
        t.join()    # 等待子线程结束
    print('主线程结束:%s'%threading.current_thread().name)
    #print("线程的数量是:", len(threading.enumerate()))
    print("当前线程:", threading.enumerate())

结果如下所示,除了主线程MainThread外,总共4个线程,每个线程运行3次,发现该结果咋一看有点奇怪,倒数第4行主线程结束了,子线程还在运行,这与join阻塞的知识点似乎不符合,实际上是这么理解,主线程并没有结束,只是恰好打印了那句"主线程结束"的话,通过threading.enumerate()查看当前线程也可证明MainThread主线程还在

见此解释:https://blog.csdn.net/fivedoumi/article/details/51863931

3.使用Thread子类创建线程

通过定义一个子类,使其继承threading.thread来创建线程.

例子如下:

# _*_ coding: UTF-8 _*_
import threading,time

class SubThread(threading.Thread):
    def run(self):  # 重写run函数
        for i in range(3):
            time.sleep(1)
            msg = "子线程" + self.name + "执行,i=" +str(i) #name为当前线程名称
            print(msg)

if __name__ == '__main__':
    print('---主线程开始---')
    t1 = SubThread()  # 创建子线程
    t2 = SubThread()
    t1.start()   # 启动子线程
    t2.start()
    t1.join()    # 等待子线程,所有子线程结束后,主线程才结束
    t2.join()
    print('主线程结束')

4.线程间通信

进程是不能共享信息的,而线程是可以共享信息的,即一个全局变量可以被多个线程修改。如下例子:

# _*_ coding: UTF-8 _*_
from threading import Thread

def plus():
    print('加线程开始')
    global g_num
    g_num += 5
    print('g_num is %d' % g_num)
    print('加线程结束')

def minus():
    print('减线程开始')
    global g_num
    g_num -= 3
    print('g_num is %d' % g_num)
    print('减线程开始')

g_num = 2
if __name__ == '__main__':
    print('主线程开始')
    print('g_num is %d' % g_num)
    t1 = Thread(target=plus)   # 实例化线程t1
    t2 = Thread(target=minus)  # 实例化线程t2
    t1.start()  # 开启线程
    t2.start()
    t1.join()
    t2.join()
    print('主线程结束')

结果如下:即 2+5-3

5.线程间同步之互斥锁

从上个例子中可以看出线程可以对全局变量值任意改动,可能会造成多个线程对同一个全局变量的混乱操作。

可用互斥锁(Mutex),防止多个线程同时写一块内存区域。互斥锁为资源引入一个状态:锁定和非锁定,某个线程要更改数据时,先将其锁定,此时资源状态为“锁定”,别的线程不能更改,直到该线程释放资源,状态为“非锁定”时,其它线程才能锁定该资源。例子如下:

# _*_ coding: UTF-8 _*_

from threading import Thread,Lock  #引入线程和锁模块
import time
n = 50    # 100张门票

def task():
    global n
    mutex.acquire()
    temp = n
    time.sleep(0.1)
    n = temp - 1
    print('购买成功,剩余%d张电影票'% n)
    mutex.release()

if __name__ == "__main__":
    mutex = Lock()    #实例化Lock类
    t_l = []
    for i in range(10):
        t = Thread(target=task)  # 实例化线程
        t_l.append(t)            # 线程放入列表
        t.start()
    for j in t_l:
        j.join()    # 等待子线程结束


结果如下:

如果没用锁,则结果如下:线程同时操作变量后果

因此在多线程开发中,对于需要写的全局变量,为防止数据混乱,通常使用互斥锁

Reference

《Python从入门到项目实践》明日科技

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值