python多任务之多线程

我们在编写程序时,若我们编写的是一个爬虫程序,当下载数据较大时,那么单机爬虫就会显得力不从心,速度很慢并且效率也不高,那么应该怎么解决这个问题呢?我们可以使用多线程来解决它。

创建多线程

这里举了一个例子

import threading
import time


def sing():
    for i in range(5):
        print("正在唱歌...")
        time.sleep(2)


def dancing():
    for i in range(5):
        print("正在跳舞...")
        time.sleep(2)


def main():
    t1 = threading.Thread(target=sing)  # 创建线程对象
    t2 = threading.Thread(target=dancing)
    t1.start()  # 执行线程
    t2.start()

当我们要创建线程时,使用 threading.Thread(target=函数名) 即可,如我们想要传递参数,这个模块中还可以添加 threading.Thread(target=函数名, args=(元组))
运行程序:可以看出程序在一起执行,执行时间会缩小一倍!
在这里插入图片描述

循环查看线程名称

在threading模块中可以使用threading.enumerate() 查看当前程序运行时的线程的名称。
这里有一个例子:可以循环查看当前线程的运行状况。

import threading
import time


def test1(num):
    for i in range(num):
        print("-----test1 %d-----" % i)
        time.sleep(1)  # 当子线程全部结束时, 主线程才会结束,如果主线程先结束,那么子线程不会被运行


def test2(num):
    for i in range(num):
        print("----test2 %d -----" % i)
        time.sleep(1)


def main():

    # 在传入参数时,应传入一个元组类型
    t1 = threading.Thread(target=test1, args=(5,))
    t2 = threading.Thread(target=test2, args=(10,))

    t1.start()
    t2.start()
    while True:
        print(threading.enumerate())
        if len(threading.enumerate()) <= 1:
            break
        time.sleep(1)


if __name__ == '__main__':
    main()

在类中使用多线程

如果我们是在函数中使用多线程, 那么只需要在main()方法中创建函数的多线程对象,然后调用start方法就可以了
那么怎么在类中执行多线程呢?

  • 在类中使用多线程:这个class应该继承于 threading.Thread模块
  • 在这个类中必须定义run方法,因为它会自动调用run方法中的内容
  • 创建类对象,然后对象.start()即可启动线程

举例:

import threading
import time


class Test(threading.Thread):  # 这个类需要继承自threading中的Thread模块
    def run(self):
        for i in range(3):
            time.sleep(1)
            print("------im %d=------" % i)
        self.login()
        self.register()

    def login(self):  # 如果类中有多个函数, 那么我可以把函数封装到run函数中
        print("这是登录")

    def register(self):
        print("这是注册。。。")


if __name__ == '__main__':
    # 创建类对象
    t = Test()
    # t会自动执行run函数中的代码,所以我们只需要调用start即可
    t.start()

结果如下:
在这里插入图片描述

多线程共享全局变量

测试全局共享变量,在使用不可变类型是需使用global进行声明, 不可变类型: 元组、数字、字符串
这里定义了两个函数,用来测试一个数字的改变状况

num = 100


def test1():  # 定义函数test1,修改num的值
    global num  # 将num修改为全局变量
    num += 1
    print("----test1: num=%d" % num)


def test2():  # 打印num值,查看结果
    print("----test2: num=%d" % num)


def main():
    # 创建两个函数的线程对象
    t1 = threading.Thread(target=test1)
    t2 = threading.Thread(target=test2)

    t1.start()

    t2.start()
    time.sleep(1)

运行结果:
在这里插入图片描述

使用互斥锁解决资源竞争的问题

当线程的运行次数过多时,那么它们之间就会产生资源竞争,导致结果不在那么准确

import threading
import time

g_num = 0


def test1(num):
    global g_num
    for i in range(num):
        g_num += 1
    print("----test1:g_num=%d" % g_num)


def test2(num):
    global g_num  # 因为要修改g_num的值,所以需要将它设置为全局变量
    for i in range(num):
        g_num += 1
    print("--test2: g_num=%d" % g_num)


def main():
    # 传入参数时用args参数传递一个元组
    t1 = threading.Thread(target=test1, args=(1000000,))  # 当传入数据过大时,就会出现资源争夺的问题
    t2 = threading.Thread(target=test2, args=(1000000,))  # 循环遍历100万次
    t1.start()
    t2.start()
    time.sleep(3)
    print("----main: g_num= %d" % g_num)

if __name__ == '__main__':
    main()

正常情况下:

  • tes1因该为 1000000
  • test2因该为 2000000
  • main因该为 2000000
    但是运行结果如下:
    在这里插入图片描述
    这就产生了资源抢夺的问题。那么因该怎么解决这种问题呢?互斥锁就该闪亮登场了,
    什么时互斥锁:简单来说,就是只有都当你上锁这个程序完成后,后面的程序才能继续运行。通俗的讲,就是前面一个人去上厕所,而他把门上锁了,只有当他上完厕所之后,将门打开,你才能上厕所,就是这个道理。我们就用上面这个例子,使用互斥锁它们不在资源竞争。
import threading
import time

g_num = 0
lock = threading.Lock()  # 创建互斥锁


def test1(num):
    global g_num
    lock.acquire()  # 上锁
    for i in range(num):
        g_num += 1
    lock.release()  # 当程序执行完毕时,进行释放
    print("----test1:g_num=%d" % g_num)


def test2(num):
    global g_num  # 因为要修改g_num的值,所以需要将它设置为全局变量
    with lock:  # 互斥锁操作,当with内部代码块执行完毕时,它会自动释放
        for i in range(num):
            g_num += 1

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


def main():
    """传入参数时用args参数传递一个元组"""
    thread_list = []  # 创建线程池
    t1 = threading.Thread(target=test1, args=(1000000,))
    thread_list.append(t1)
    t2 = threading.Thread(target=test2, args=(1000000,))

    thread_list.append(t2)
    for t in thread_list:
        t.start()
        t.join()  # 让子线程先完成,主线程最后执行

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


if __name__ == '__main__':
    main()

结果:
在这里插入图片描述
掌握了以上的内容,应该可以满足日常工作中的多线程需求了。
后面会更新多任务中的另一种方式—多进程

总结

没有总结

溜了溜了

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值