线程

线程

在一个进程的内部,要同时干多件事,就需要同时运行多个“子任务”,我们把进程内的这些“子任务”叫做线程。

线程通常叫做轻型的进程。线程是共享内存空间的并发执行的多任务,每一个线程都共享一个进程的资源。

线程是最小的执行单元,而进程由至少一个线程组成。如何调度进程和线程,完全由操作系统决定,程序自己不能决定什么时候执行,执行多长时间。

模块
1、_thread模块 低级模块,接近底层。
2、threading模块 高级模块,对_thread进行了封装

线程基本用法

基本跟进程类似。

from threading import Thread, current_thread
import time

def run(num):
    print('子线程(%s)开始' % (current_thread().name,))
    time.sleep(2)
    print('打印', num)
    time.sleep(2)
    print('子线程(%s)结束' % (current_thread().name,))


if __name__ == '__main__':
    # 任何进程默认就会启动一个线程,称为主线程,主线程可以启动新的子线程
    # current_thread():返回返回当前线程的实例
    print('主线程(%s)开始' % (current_thread().name,))
    # 创建子线程
    t = Thread(target=run, args=(1,), name='runThread')
    t.start()
    # 等待线程结束
    t.join()
    print("主线程(%s)结束" % (current_thread().name))
常见方法
方法名说明
isAlive()返回线程是否在运行。正在运行指启动后、终止前。
get/setName(name)获取/设置线程名。
start()线程准备就绪,等待CPU调度
is/setDaemon(bool)获取/设置是守护线程(默认前台线程(False))。(在start之前设置)
join([timeout])阻塞当前上下文环境的线程,直到调用此方法的线程终止或到达指定的timeout(可选参数)
线程间共享数据

线程数据是共享的。先来看一个简单的例子。

from threading import Thread
from time import sleep


# 全局数据
num = 100


def run():
    print('子线程开始')
    global  num
    num += 1
    print('子线程结束')


if __name__ == '__main__':
    print('主线程开始')
    # 创建主线程
    t = Thread(target=run)
    t.start()
    t.join()
    print(num)
    print('主线程结束')

执行结果:

主线程开始
子线程开始
子线程结束
101
主线程结束

可以看到子线程修改的全局变量,在主线程中也体现出来了。

线程之间数据共享引发的问题

多线程和多进程最大的不同在于,多进程中,同一个变量,各自有一份拷贝存在每个进程中,互不影响。而多线程中,所有变量都由所有线程共享。所以,任何一个变量都可以被任意一个线程修改,因此,线程之间共享数据最大的危险在于多个线程同时修改一个变量,容易把内容改乱了。

下面来模拟这个问题:

from threading import Thread


# 全局变量
num = 100

def run(n):
    global num
    for i in range(100000000):
        num = num + n
        num = num - n


if __name__ == '__main__':
    t1 = Thread(target=run, args=(6,))
    t2 = Thread(target=run, args=(9,))
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print('num=',num)

运行之后发现num不等于100了。这就是因为两个线程都对num进行操作,中间发生了紊乱。

使用线程锁解决数据混乱问题

threading中的Lock类表示锁。

锁确保了这段代码只能由一个线程从头到尾的完整执行。阻止了多线程的并发执行,包含锁的某段代码实际上只能以单线程模式执行,所以效率大大滴降低了。

由于可以存在多个锁,不同线程持有不同的锁,并试图获取其他的锁,可能造成死锁,导致多个线程挂起。只能靠操作系统强制终止。

我们给之前的代码加上锁 来解决数据混乱的问题。

from threading import Thread, Lock


# 全局变量
num = 100
# 锁对象
lock = Lock()

def run(n):
    global num
    global lock
    for i in range(100000000):
        # 获取锁
        lock.acquire()
        try:
            num = num + n
            num = num - n
        finally:
            # 修改完一定 要释放锁
            lock.release()


if __name__ == '__main__':
    t1 = Thread(target=run, args=(6,))
    t2 = Thread(target=run, args=(9,))
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print('num=',num)

使用上下文管理器 with,可以自动获取锁,释放锁。可以将上面代码的try语句改成如下:

with lock:
	num = num + n
	num = num - n
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值