python线程(基础知识和用法)

1.线程

线程是操作系统资源调度的最小单位,一个进程最少有一个线程。同一个进程的线程可以资源共享。

前台线程(默认):主线程执行结束后会等待子线程结束完后一起退出释放资源。

后台线程:主线程执行结束就退出。

# 设置前台线程        
t.setDaemon(False)
# 设置后台线程
t.setDaemon(True)

2.开启5个线程访问百度

import threading
import time
import requests

def get_content(url):
    result = requests.get(url).text
    time.sleep(0.5)
    print("get url")


# 计时装饰器
def runtime(func):
    def inner(*args, **kwargs):
        print("start.......")
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"花了{end_time-start_time}s")
        return result
    return inner

@runtime
def main():
    for i in range(5):
        # target必须是一个callable对象
        target = threading.Thread(target=get_content, args=("http://www.baidu.com",))
        target.start()

main()

根据运行结果显示

只花了0.003秒,这就是多线程的好处,如果不使用多线程,我们的程序只能顺序执行,所以整个程序执行结束至少需要2.5s,使用多线程就大大降低了我们的时间消耗。主线程只需要告诉子线程去访问百度,至于子线程怎么去访问百度主线程是不关心的,主线程只是一个发号施令者。

但是在工作场景下,可以加一个阻塞模式,阻塞当前上下文,等子线程结束以后一起退出

import threading
import time
import requests

def get_content(url):
    result = requests.get(url).text
    time.sleep(0.5)
    print("get url")


# 计时装饰器
def runtime(func):
    def inner(*args, **kwargs):
        print("start.......")
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"花了{end_time-start_time}s")
        return result
    return inner

@runtime
def main():
    lst = []
    for i in range(5):
        target = threading.Thread(target=get_content, args=("http://www.baidu.com",))
        target.start()
        lst.append(target)

    for target in lst:
        target.join()


main()

等在子线程一起结束的结果是,很显然多线程的效率还是比顺序执行高了很多。

 3.自定义线程类

from threading import Thread
# 自定义线程类:采用继承的方式自定义类
class MyThread(Thread):
    def __init__(self, num):
        # 重写init函数,super()重新执行父类的init函数
        super().__init__()
        self.num = num

    def run(self):
        print(f"running...{self.num}")


t1 = MyThread(1)
t2 = MyThread(2)

t1.start()
t2.start()

 4.线程锁

由于同一个进程内的线程是资源共享的,但是资源紧缺的时候,线程间就会产生资源抢夺问题,进而产生意想不到的脏数据(错误数据)。

4.1 互斥锁:允许多个线程进行资源抢夺,但是同一时刻只能由一个线程可以访问资源。

(提示:互斥锁最好在有资源抢夺的时候再用,如果全程加锁多线程会失去效果)

Lock 原始锁:在获取锁之前一直处于等待状态,直到获取到锁以后才往下执行
RLock 重入锁:在获取锁之前判断是否已经获取到锁,如果没有获取到锁就处于等待状态,如果已经获取到锁就往下执行。
(建议:在我们的开发环境中最好还是使用重入锁,原始锁可能会在我们不想要地方卡住,导致程序无法继续执行)

import threading
lock1 = threading.Lock()
lock2 = threading.RLock()

lock1.acquire()
print("lock1 acquired 1")
lock1.acquire()
print("lock1 acquired 1 again")
lock1.release()
print("lock1 release 1")
lock1.release()
print("lock1 release 1 again")

# lock1 acquired 1
# 产生死锁



lock2.acquire()
print("lock2 acquired 2")
lock2.acquire()
print("lock2 acquired 2 again")
lock2.release()
print("lock2 release 2")
lock2.release()
print("lock2 release 2 again")

# lock2 acquired 2
# lock2 acquired 2 again
# lock2 release 2
# lock2 release 2 again

原始锁使用方法,重入锁只是将Lock改成RLock

from threading import Lock

# 创建一个锁实例
lock = Lock()

# 在要加锁的部分的开始加上
lock.acquire()

# 在锁的末尾加上
lock.release()

4.2信号量:设置同一时刻最多有几个线程可以访问公共资源

4.3事件锁:根绝状态,确定是否通过事件,主线程控制其他线程是否可以访问系统资源

4.4条件锁:事件锁和信号量的结合,当满足条件时,控制n个线程可以访问公共资源。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值