【python基础】多任务编程之多线程

1、线程特征

线程特征:
    1、一个进程可包含多个线程
    2、一个进程中的所有线程共享这个进程的资源
    3、多个线程的运行互不影响
    4、线程的创建和销毁消耗的资源远小于进程
    5、各个线程也有自己的ID等特征

2、threading模块创建线程

threading模块创建线程:
    1、创建线程对象:
        from threading import Thread
        t = Thread()
        功能:创建线程对象
        参数:target绑定线程函数
            args:元组,给线程函数位置传参
            kwargs:字典,给线程函数键值传参

    2、启动线程:
        t.start()

    3、回收线程:
        t.join([timeout])

示例如下:

import time
from threading import Thread
from time import sleep

def func(sec, name):
    sleep(sec)
    print("%s已执行" % name)

#创建多个线程来执行func,并统计执行时间
start = time.time()

th = []		#创建列表存放线程对象,统一回收
for i in range(5):
    t = Thread(target=func, args=(2,), kwargs={"name":"T%d" % i})
    th.append(t)
    t.start()

for i in th:
    i.join()
print("执行时间:%fs" % (time.time() - start))

运行结果:

T2已执行T1已执行
T0已执行
T3已执行T4已执行


执行时间:2.010124s

4、线程间通信

1、通信方法:线程间使用全局变量进行通信
2、共享资源争夺:
    共享资源:多个进程或线程都可以操作的资源称为共享资源,对共享资源的操作代码段称为临界区
    影响:对共享资源的无序操作可能会带来数据的混乱,或者操作错误,此时往往需要同步互斥机制协调操作顺序
3、同步互斥机制:
    同步:同步是一种协作关系,为完成操作,多进程或线程间形成一种协调,按照必要的步骤有序执行操作
    互斥:互斥是一种制约关系,当一个进程或线程占有资源时会进行加锁处理,此时其他进程线程就无法操作该资源,直到解锁后才能操作。
4、线程同步互斥方法:
    线程Event
    from Threading import Event
    e = Event()                 #创建线程Event对象
    e.wait([timeout])           #阻塞等待e被set
    e.set()                     #设置e,使wait结束阻塞
    e.clear()                   #使e回到未被设置状态
    e.is_set()                  #查看当前e是否被设置

    线程锁Lock:
    from threading import Lock
    lock = Lock()               #创建锁对象
    lock.acquire()              #上锁,如果lock已经上锁再调用会阻塞
    lock.release()              #解锁

    with lock:                  #上锁
        ...
        ...
    with代码块结束自动解锁

Event示例:

以下代码中,想要实现先设置全局变量str1的值,再打印输出:

from threading import Thread,Event
from time import sleep
str1 = "abcdefg"
e = Event()

def set_str():
    sleep(0.1)
    global str1
    str1 = "1234567"

t = Thread(target=set_str)
t.start()
print(str1)
t.join()

运行结果如下:

abcdefg

可以看到,打印的结果还是未被设置的值,要想打印设置之后的值,修改代码如下:

from threading import Thread,Event
from time import sleep
str1 = "abcdefg"
e = Event()

def set_str():
    sleep(0.1)
    global str1
    str1 = "1234567"
    e.set()		# 完成赋值后,设置e,使wait状态结束


t = Thread(target=set_str)
t.start()
e.wait()		# 阻塞等待e被set
print(str1)
t.join()

结果如下:

1234567

线程锁示例:

from threading import Thread,Lock

num = 0
def add():
    with lock:      # 多个线程操作同一个全局变量时,上锁防止数据混乱
        global num
        for i in range(1000000):
            num += 1

def sub():
    lock.acquire()	# 多个线程操作同一个全局变量时,上锁防止数据混乱
    global num
    for i in range(1000000):
        num -= 1
    lock.release()

if __name__ == "__main__":
    lock = Lock()	# 创建锁对象
    t1 = Thread(target=add)
    t2 = Thread(target=sub)
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print(num)

运行结果:

0

5、死锁

死锁:两个或两个以上的线程在执行过程中,由于竞争资源或由于彼此通信而造成的一种阻塞现象,若无外力作用,他们都将无法推进下去,此时系统处于死锁状态或系统产生了死锁。
T1使用R1,请求R2;T2使用R2,请求R1

死锁产生条件:
当前线程拥有其他线程需要的资源
当前线程等待其他线程已拥有的资源
都不放弃自己拥有的资源

6、python线程GIL(全局解释器)

GIL:PYTHON解释器中加入了解释器锁,导致python解释器同一时间只能执行一个线程,降低了线程执行效率
后果:遇到阻塞时,线程会主动让出解释器,去解释其他线程,所以python多线程在执行多阻塞高延迟IO时可以提升程序效率,其他情况并不能对效率有所提升。
GIL问题建议:
    尽量使用进程完成无阻塞的并发行为
    不使用C作为解释器
结论:在无阻塞状态下,多线程程序和单线程程序执行效率几乎差不多,甚至还不如单线程效率,但是多进程运行相同内容却可以有明显效率提升。

7、进程和线程区别和联系

进程和线程区别和联系:
    1、进程的创建和删除消耗的资源比线程多
    2、进程空间独立,数据互不干扰,有专门通信方法;线程使用全局变量进行通信
    3、一个进程可以有多个分支线程,两者有包含关系
    4、多个线程共享进程资源,在共享资源操作时往往需要同步互斥处理
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值