多线程——继承Thread的类

本文详细介绍了Python中通过继承Thread类创建多线程的方法,包括实例演示线程的创建、共享全局变量、参数传递以及解决线程同步问题。强调了全局变量在多线程中的共享特性,提出了线程同步的必要性并给出了解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、通过继承Thread的类完成创建线程

上一节对于多线程的使用是一个最基本的使用,但是如果我们在代码中遇到了比较复杂的多线程任务,就很难满足我们的需求,这里就需要通过继承Thread的类来完成线程的创建

实例:
import threading
import time


class MyThread(threading.Thread):
  def run(self):
      for i in range(4):
          time.sleep(1)
          # name属性中保存的是当前线程的名字
          msg = '我是' + self.name + '@' +str(i)
          print(msg)


if __name__ == '__main__':
  t = MyThread()
  # 注意,这里一定要使用`start`,他会默认去调用线程类的run方法
  t.start()

运行结果:

我是Thread-1@0
我是Thread-1@1
我是Thread-1@2
我是Thread-1@3

上面是单线程的延时,如果是多线程,这里需要注意一点,多线程的创建一定是在线程类里面进行,在run方法进行调用,切记不可在主函数调用,不然仅仅是执行了一次普通的方法而已。
多线程实例:

import threading
import time


class MyThread(threading.Thread):
    def run(self):
        for i in range(4):
            time.sleep(1)
            # name属性中保存的是当前线程的名字
            msg = '我是' + self.name + '@' +str(i)
            self.login()
            print(msg)

    def login(self):
        for i in range(3):
            print('我登录了' + str(i) + '次')


if __name__ == '__main__':
    t = MyThread()
    t.start()

这样就完成了多线程的创建和使用。
运行结果

我登录了0次
我登录了1次
我登录了2次
我是Thread-1@0
我登录了0次
我登录了1次
我登录了2次
我是Thread-1@1
我登录了0次
我登录了1次
我登录了2次
我是Thread-1@2
我登录了0次
我登录了1次
我登录了2次
我是Thread-1@3

2、多线程共享全局变量

这里我们需要注意一点,在一个函数中,对全局变量进行修改的时候,到底是否使用global进行说明,需要看 是否对 全局变量的执行指向进行了修改

  1. 如果修改了执行,即让全局变量指向了一个新的地方,那么必须使用global
  2. 如果,仅仅修改了指向空间的数据,此时不必用global
    在多线程里面,就会共享全局变量。
    原因:一般多线程用来处理一个任务同时需要进行的操作,这个时候对象为同一个目标任务,所以一般需要对其中的变量进行共享
实例:
import threading
import time


nums = 100
def test1():
    global nums
    nums += 1
    print('-----test1-----=%d' % nums)

def test2():
    print('------test2----=%d' % nums)

def main():
    t1 = threading.Thread(target=test1)
    t2 = threading.Thread(target=test2)
    t1.start()
    time.sleep(1)

    t2.start()
    time.sleep(1)

    print('-----in main-----=%d' % nums)

if __name__ == '__main__':
    main()

运行结果:

-----test1-----=101
------test2----=101
-----in main-----=101

可以看到我们,在test2中并没有使用global进行声明,他同样打印出了经过·test1·处理过的变量,最终main函数也是,可以知道,在多线程中,是共享成员变量的

3、多线程共享全局变量——args传参

我们在进行线程的调用和执行时,是可以携带参数进行传递的

实例:
import threading
import time


def test1(temp):
    temp.append(10)
    print('----test1----=%s' % str(temp))


def test2(temp):
    print('----test2----=%s' % str(temp))


nums = [10, 20]


def main():
    # 注意,这里传递的参数必须是一个元组
    t1 = threading.Thread(target=test1, args=(nums,))
    t2 = threading.Thread(target=test2, args=(nums,))
    t1.start()
    time.sleep(1)

    t2.start()
    time.sleep(1)

    print('-----in main-----=%s' % str(nums))


if __name__ == '__main__':
    main()
运行结果:
----test1----=[10, 20, 10]
----test2----=[10, 20, 10]
-----in main-----=[10, 20, 10]

可以看到,参数已经成功进行传递,并且nums变量也为共享了全局变量

4、全局变量共享的问题

这里存在一个非常大的问题,我们先用一个实例来认识一下

实例
import threading
import time

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


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


def main():
    t1 = threading.Thread(target=test1, args=(10000000,))
    t2 = threading.Thread(target=test2, args=(10000000,))
    t1.start()
    t2.start()

    time.sleep(5)
    print('-----in main-----=%d' % g_num)


if __name__ == '__main__':
    main()

运行结果:

----test1----=11474471
----test2----=11839490
-----in main-----=11839490

可以看到,按理来说,程序中,test1=10000000,test2=10000000,最终等于20000000,可是运行结果却不是这个样子。这里就是存在的问题。来看下下面这张图。
在这里插入图片描述
我们在执行程序的时候,可能看起来是一个操作,但是cpu会将它分解为非常基础的操作去执行。如我们程序中的 g_num+=1可以从图中看出分成了三个基础步骤,而cpu在执行中,会将两个线程中的步骤进行分别执行,这就导致了,执行不一致的情况。最终,导致并没有得到我们所需的结果。

解决方法:(线程同步)
  1. 系统调用 t1 ,然后获取到g_num的值为0,此时上一把锁,即不允许其他线程操作g_num
  2. t1 对g_num的值进行+1
  3. t1 解锁,此时g_num的值为1,其他线程就可以使用g_num了,而且此时g_num的值不是0,而是1
  4. 同理其他线程在对g_num进行修改时,都要先上锁,处理完后在解锁,在上锁的整个过程中不允许其他线程访问,就保证了数据的正确性。
拓展

这里引入了一个概念(同步),同步就是协同步调,按照预订的先后次序进行运行。比如我们这里的线程同步,就是将线程A和B一块配合,A执行到一定程度时要依靠B的某种结果,于是停下来,示意B运行,B执行后,在将结果给A,A再操作。而不是A和B互相随便插入cpu进行操作
具体在实际中的操作,请见下一节的互斥锁和死锁

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值