Python多任务编程-线程创建与多线程实例 threading.Thread()

1.线程的介绍

  • 在Python中,想要实现多任务除了使用进程,还可以使用线程来完成,线程是实现多任务的另外一种方式。

  • 线程的概念:线程是进程中执行代码的一个分支,每个执行分支(线程)要想工作执行代码需要cpu进行调度,也就是说线程是cpu调度的基本单位,每个进程至少都有一个线程,而这个线程就是主线程。

  • 线程的作用:多线程可以在同一片内存空间完成多任务

2.线程创建与多线程

  • 导入线程模块

# 导入线程模块
import threading
  • 线程类Thread ——创建线程与参数说明

    def func(data):
        return
    ​
     # 以元组的方式给执行任务传参
     t1 = threading.Thread(target=func,args=('python',),name='t1')
     # 以字典方式给执行任务传参
     t2 = threading.Thread(target=func,kwargs={'data':'itcast'},name='t2')
    1. 格式:Thread(group , target , name , args , kwargs])

    2. group: 线程组,目前只能使用None

    3. target: 执行的目标任务名

    4. 线程参数:

      • args: 以元组的方式给执行任务传参

      • kwargs: 以字典方式给执行任务传参

    5. name: 线程名,一般不用设置

    6. daemon:设置守护线程

    7. t1.start():启动线程执行任务

    8. threading.current_thread().name:获取当前执行线程的名称

创建线程与启动完整代码展示:

# 导入线程模块
import threading
​
def func(data):
    print('线程使用')
    print(f'参数数据:{data}')
    # 获取当前执行线程的名称
    print('线程名称:',threading.current_thread().name)
​
if __name__ == '__main__':
​
    # 创建线程
    # group = None, 使用默认
    # target = None,  指定函数方法
    # name = None, 指定线程名称
    # args = (), kwargs = None, 传递参数
    # daemon = None 设置守护线程
    t1 = threading.Thread(target=func,args=('python',),name='t1')
    t2 = threading.Thread(target=func,kwargs={'data':'itcast'},name='t2')
    # 启动运行线程
    t1.start()
    t2.start()

3.线程的注意点

  1. 线程之间执行是无序的

    • 线程之间执行是无序的,它是由cpu调度决定的 ,cpu调度哪个线程,哪个线程就先执行,没有调度的线程不能执行。

    • 进程之间执行也是无序的,它是由操作系统调度决定的,操作系统调度哪个进程,哪个进程就先执行,没有调度的进程不能执行。

  2. 主线程会等待所有的子线程执行结束再结束

    • 如何让主进程退出子进程销毁,不让主进程再等待子进程去执行。——设置守护主线程

      • 第一种设置守护线程:daemon=True

      • 第二种:线程对象.setDaemon(True)

        # 1.创建线程时传递守护进程参数 daemon=True
        t1 = threading.Thread(target=func,name='t1',daemon=True)
        
        # 2.线程对象调用 setDaemon(True)
        t1.setDaemon(True)
    import threading
    # 主线程会等待子线程结束后在结束
    ​
    def func():
        print('线程关系')
        print('子线程:',threading.current_thread().name)
    ​
    if __name__ =="__main__":
    ​
        # 创建线程
        t1 = threading.Thread(target=func,name='t1',daemon=True)
        t2 = threading.Thread(target=func,name='t2')
        # 调用
        t1.start()
        t2.start()
        # 默认情况下主线程会等待所有子线程结束后才真正结束主线程程序
        # 可以通指定守护线程的形式,当主线程结束后自动结束子线程
        t2.setDaemon(True)
        print('主线程')
  3. 线程之间共享全局变量

    import threading
    ​
    data_list = []
    ​
    def write_data():
        # 往全局列表中写入数据
        for i in range(0, 50):
            data_list.append(i)
        print('write_data方法写入的数据为:', data_list)
    ​
    ​
    def read_data():
        print('read_data方法读取的数据为:', data_list)
    ​
    if __name__ =='__main__':
    ​
        # 创建多线程程分别调用两个读写方法,验证全局变量是否共享数据
        t1 = threading.Thread(target=write_data)
        t2 = threading.Thread(target=read_data)
        t1.start()
        t2.start()
    ​
        print('主线程读取的数据:',data_list)
    write_data方法写入的数据为: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49]
    read_data方法读取的数据为: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49]
    主线程读取的数据: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49]
    ​

    通过上述代码展示:线程 t1 与线程 t2 分别执行对全局列表 data_list 的写入与读取操作·,不难发现,t2读取的数据与总线程读取的数据均为t1写入的数据。所以:线程之间共享全局变量

  4. 线程之间共享全局变量数据出现错误问题(线程的资源抢占)

    • 在执行多线程代码时,有时会发现全局变量数据不一样?                                            错误分析: 例如 两个线程first_thread和second_thread都要对全局变量g_num(默认是0)进行加1运算,但是由于是多线程同时操作,有可能出现下面情况:在g_num=0时,first_thread取得g_num=0。此时系统把first_thread调度为”sleeping”状态,把second_thread转换为”running”状态,t2也获得g_num=0 然后second_thread对得到的值进行加1并赋给g_num,使得g_num=1。然后系统又把second_thread调度为”sleeping”,把first_thread转为”running”。线程t1又把它之前得到的0加1后赋值给g_num。 这样导致虽然first_thread和first_thread都对g_num加1,但结果仍然是g_num=1

    • 全局变量数据错误的解决办法:利用线程同步: (.join())

      • 保证同一时刻只能有一个线程去操作全局变量 同步: 就是协同步调,按预定的先后次序进行运行。

      • t1.start()
        t1.join()
        ​
        t2.start()
        t2.join()

        案例展示

import  threading
data = 0
​
def func1():
    global data
    for i in range(0,1000000):
        data+=1
​
    print(f'函数1的累加结果:{data}')
​
​
def func2():
    global data
    for i in range(0, 1000000):
        data += 1
​
    print(f'函数2的累加结果:{data}')
​
if __name__ == '__main__':
    # 创建两个线程进程累加
    t1 = threading.Thread(target=func1)
    t2 = threading.Thread(target=func2)
    # 通过join的形式让函数顺序执行
    t1.start()
    # t1.join()
    t2.start()
    # t2.join()
    print(f'主线程的结果展示:{data}')
主线程的结果展示:506845
函数1的累加结果:1383100
函数2的累加结果:1285542

4. 进程与线程对比

  • 进程和线程都是完成多任务的一种方式

  • 多进程要比多线程消耗的资源多,但是多进程开发比单进程多线程开发稳定性要强,某个进程挂掉不会影响其它进程。

  • 多进程可以使用cpu的多核运行,多线程可以共享全局变量。

  • 线程不能单独执行必须依附在进程里面

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值