多任务之线程

  • 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/kun1280437633/article/details/80320488

1、什么是并发和并行

并发:指的是任务数多余cpu核数,通过操作系统的各种任务调度算法,实现用多个任务“一起”执行(实际上总有一些任务不在执行,因为切换任务的速度相当快,看上去一起执行而已)

并行:指的是任务数小于等于cpu核数,即任务真的是一起执行的

2、 python的thread模块是比较底层的模块,python的threading模块是对thread做了一些包装的,可以更加方便的被使用

示例代码:

# 当程序开始执行,解释器会自动创建主线程,执行程序代码
import threading  # 1. 导入 threading 模块
import time

def work1():
    for i in range(2000):

        print('正在搬砖:', i)

def work2():
    for i in range(2000):
        print('正在扫地:', i)

def main():
   
"""开启线程,实现多任务执行"""
    print('main--start---',threading.enumerate())

    t1 = threading.Thread(target=work1)  # 当创建新子线程对象的时候,线程没有开始运行

    print('创建子线程对象---',threading.enumerate())

扫描二维码关注公众号,回复: 1040830 查看本文章

    t2 = threading.Thread(target=work2)

    t1.start()  # 当调用 start 之后,线程才开始运行

    print('子线程开始运行---',threading.enumerate())

    t2.start()

    #如果主线程被杀死时还有子线程在运行,则所有子线程会一起死掉
    print("结束啦")

if __name__ == '__main__':

    main()

注意:(1)主线程会等待子线程全部结束后才会结束,主线程死亡,子线程立即死亡

          (2)多个任务之间会争夺CPU资源,什么时候能抢到时间片是随机的,每一次争夺到的时间片长度都是随机的

          (3)多任务的切换是无序的

3、自定义类实现线程

  • python的threading.Thread类有一个run方法,用于定义线程的功能函数,可以在自己的线程类中覆盖该方法。而创建自己的线程实例后,通过Thread类的start方法,可以启动该线程,交给python虚拟机进行调度,当该线程获得执行的机会时,就会调用run方法执行线程。

代码:

# 当程序开始执行,解释器会自动创建主线程,执行程序代码
import threading  # 1. 导入 threading 模块
import time

class KHThread(threading.Thread): # 1.定义类
    def run(self):  # 2.提供 run 方法
        for i in range(5):
            print('正在搬砖:', i)
            time.sleep(0.5)

def main():
    """开启线程,实现多任务执行"""
    # 3.创建线程对象
    # t1 = threading.Thread(target=work1)
    t1 = KHThread()

    # 4.开启线程,执行 run 函数
    t1.start()
    print(t1)  # 自定线程类,可以方便的了解到线程提供了什么功能

if __name__ == '__main__':

    main()

4、共享数据

  • 在一个进程内的所有线程共享全局变量,很方便在多个线程间共享数据
  • 缺点就是,线程是对全局变量随意遂改可能造成多线程之间对全局变量的混乱(即线程非安全)

代码

import threading
import time

def work1(tmp):
    tmp.append(11) 
# t1 线程修改列表数据
    #tmp["nam"] = "gaohan"
    print('work1--', tmp)

def work2(tmp):
    print('work2--', tmp)  # t2 线程可以获取到数据

def main():
    """两个线程间通过传参共享数据"""
    ls = []

    t1 = threading.Thread(target=work1, args=(ls,))  # 向线程传参,使用 args 关键字参数,传递的值必须是元组
    t2 = threading.Thread(target=work2, args=(ls,))

    t1.start()
    time.sleep(1)
    t2.start()

if __name__ == '__main__':

    main()

结果:

work1-- [11]
work2-- [11]

出现问题的代码:

import threading

def work1():
    global num
    for i in range(1000000):
        num += 1
    print('work1--', num)

def work2():
    global num
    for i in range(1000000):
        num += 1
    print('work2--', num)

num = 0

def main():
 
  """开启两个线程,修改同一个全局变量"""
    t1 = threading.Thread(target=work1)
    t2 = threading.Thread(target=work2)

    t1.start()

    t2.start()

if __name__ == '__main__':

    main()

结果

work1-- 1335864

work2-- 1387952

5、使用互斥锁解决线程间的资源竞争

import threading
"""
1. 要达到多个线程同时运行的效果,上锁的代码范围要尽量的小
2. 大量的加锁和解锁比较消耗时间,应该尽量减少加锁和解锁的次数
"""

def work1(lock):
    global num
    for i in range(1000000):
        lock.acquire()  # 获取锁
        num += 1

        if i%10000 == 0:
            print('work1---', i)
        lock.release()  # 释放锁

    print('work1--', num)

def work2(lock):
    global num

    for i in range(1000000):
        lock.acquire()  # 获取锁
        num += 1

        if i%10000 == 0:
            print('work2---', i)
        lock.release()  # 释放锁

    print('work2--', num)

num = 0

def main():
    """开启两个线程,修改同一个全局变量"""
    lock = threading.Lock()  # 创建锁
    t1 = threading.Thread(target=work1, args=(lock,))
    t2 = threading.Thread(target=work2, args=(lock,))

    t1.start()
    t2.start()

if __name__ == '__main__':

    main()

6、死锁

#coding=utf-8
import threading
import time

class MyThread1(threading.Thread):
    def run(self):
     
  # 对mutexA上锁
        mutexA.acquire()

        # mutexA上锁后,延时1秒,等待另外那个线程 把mutexB上锁
        print(self.name+'----do1---up----')
        time.sleep(1)

        # 此时会堵塞,因为这个mutexB已经被另外的线程抢先上锁了
        mutexB.acquire()
        print(self.name+'----do1---down----')
        mutexB.release()

        # 对mutexA解锁
        mutexA.release()

class MyThread2(threading.Thread):
    def run(self):
        # 对mutexB上锁
        mutexB.acquire()

        # mutexB上锁后,延时1秒,等待另外那个线程 把mutexA上锁
        print(self.name+'----do2---up----')
        time.sleep(1)

       
# 此时会堵塞,因为这个mutexA已经被另外的线程抢先上锁了
        mutexA.acquire()
        print(self.name+'----do2---down----')
        mutexA.release()

        # 对mutexB解锁
        mutexB.release()

mutexA = threading.Lock()
mutexB = threading.Lock()

if __name__ == '__main__':
    t1 = MyThread1()
    t2 = MyThread2()
    t1.start()
    t2.start()

猜你喜欢

转载自blog.csdn.net/kun1280437633/article/details/80320488