并行程序-线程(一)

进程-内存分配单元
线程-CPU调度单元(箭头),操作系统真正调动的是线程
主线程必须等子线程结束后才会结束。在这里插入图片描述
进程和线程之间的一个区别是:进程之间不共享全局变量,而线程之间共享全局变量,这是线程的一个优点,即不需要像进程一样单独通过队列等方式来共享变量,而是直接共享,但也是一个缺点。
在这里插入图片描述

# coding=utf-8

from threading import Thread
import time

g_num = 0

def test1():
    global g_num
    for i in range(1000000):
        g_num += 1

    print("---test1---g_num=%d"%g_num)

def test2():
    global g_num
    for i in range(1000000):
        g_num += 1

    print("---test2---g_num=%d"%g_num)


p1 = Thread(target=test1)
p1.start()

#time.sleep(3) #取消屏蔽之后 再次运行程序,结果会不一样,,,为啥呢?

p2 = Thread(target=test2)
p2.start()

print("---g_num=%d---"%g_num)


# ---g_num=296748---
# ---test2---g_num=1348783
# ---test1---g_num=1776224


# 取消屏蔽之后
# ---test1---g_num=1000000
# ---g_num=1207917---
# ---test2---g_num=2000000

在屏蔽的情况下,为什么会出现g_num不到1000000呢?看下图
在这里插入图片描述
对于每个线程,加1和赋值操作是分开的两步,可能会出现如下情况:cpu先调用线程1进行加1操作,但是还没来得及进行赋值便调用线程2执行相同的加1操作,而后再分别调用1和2进行赋值操作,这期间进行了两次加1,但实际上只加了1,所以g_num最终不到2000000

如何避免上述情况,使得各线程之间不受到影响?加条件语句g_flag

在这里插入图片描述

这样子可以避免加1操作进行重复,但是这样就好了吗?

这样结果虽然避免了各线程之间受影响,但是效率却很低,因为g_flag=1时,满足线程1的条件,期间CPU调用线程2时,一直在判断是否满足条件g_flag !=1,这样就占用了CPU资源,做了很多无用功。

那应该如何提高CPU利用率呢?给每个线程上互斥锁

#创建锁
mutex= threading.Lock()
#锁定
mutex.acquire()
#释放
mutex.release()

一旦给一个进程上了锁,其他进程只能等待,相当于睡觉,不会占用CPU资源,因此效率会提高很多。

# coding=utf-8

from threading import Thread, Lock
import time

g_num = 0

def test1():
    global g_num
    #这个线程和test2线程都在抢着 对这个锁 进行上锁,如果有1方成功的上锁,那么导致另外
    #一方会堵塞(一直等待)到这个锁被解开为止
    mutex.acquire()
    for i in range(1000000):
        g_num += 1
    mutex.release()#用来对mutex指向的这个锁 进行解锁,,,只要开了锁,那么接下来会让所有因为
                    #这个锁 被上了锁 而堵塞的线程 进行抢着上锁

    print("---test1---g_num=%d"%g_num)

def test2():
    global g_num
    mutex.acquire()
    for i in range(1000000):
        g_num += 1
    mutex.release()

    print("---test2---g_num=%d"%g_num)

#创建一把互斥锁,这个锁默认是没有上锁的
mutex = Lock()

p1 = Thread(target=test1)
p1.start()

#time.sleep(3) #取消屏蔽之后 再次运行程序,结果会不一样,,,为啥呢?

p2 = Thread(target=test2)
p2.start()

print("---g_num=%d---"%g_num)

 
# ---g_num=653790---
# ---test1---g_num=1000000
# ---test2---g_num=2000000

注意:
多线程上锁,是为了让多个线程一个一个访问他们共有的资源,上锁之后,类似于单线程。那所谓的并行是指的什么呢?只指在多核的情况下,只有多核的时候,才能同时执行多个任务。

线程的同步

同步使得线程可以有序的去执行

# coding=utf-8

from threading import Thread,Lock
from time import sleep

class Task1(Thread):
    def run(self):
        while True:
            if lock1.acquire():
                print("------Task 1 -----")
                sleep(0.5)
                lock2.release()

class Task2(Thread):
    def run(self):
        while True:
            if lock2.acquire():
                print("------Task 2 -----")
                sleep(0.5)
                lock3.release()

class Task3(Thread):
    def run(self):
        while True:
            if lock3.acquire():
                print("------Task 3 -----")
                sleep(0.5)
                lock1.release()

#使用Lock创建出的锁默认没有“锁上”
lock1 = Lock()
#创建另外一把锁,并且“锁上”
lock2 = Lock()
lock2.acquire()
#创建另外一把锁,并且“锁上”
lock3 = Lock()
lock3.acquire()

t1 = Task1()
t2 = Task2()
t3 = Task3()

t1.start()
t2.start()
t3.start()


# ------Task 1 -----
# ------Task 2 -----
# ------Task 3 -----
# ------Task 1 -----
# ------Task 2 -----
# ------Task 3 -----
# ------Task 1 -----
# ------Task 2 -----

总结
锁的好处:
确保了某段关键代码只能由⼀个线程从头到尾完整地执行。
锁的坏处:
阻⽌了多线程并发执⾏,包含锁的某段代码实际上只能以单线程模式执
⾏,效率就⼤⼤地下降了
由于可以存在多个锁,不同的线程持有不同的锁,并试图获取对⽅持有
的锁时,可能会造成死锁

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值