多任务(线程、进程)

什么是多任务

  • 简单地说,就是同时可以运行多个任务。

一、线程

  • 提问?

如果一个程序想同时执行多个部分的代码,那么基本有2种方式实现:
线程
进程

  • 什么是线程

我们把运行的代码可以当作一个河流主干流,而线程就是一个分支运行流程,最后和主干流合并。

  • 多线程执行
import threading
import time
 
def say_sorry():
	print("亲爱的,我错了,我能吃饭了吗?")
	time.sleep(1)
 

for i in range(5):
    t = threading.Thread(target=say_sorry) # 创建线程
    t.start()  # 启动线程,即让线程开始执行
  • 创建线程的另外一种方式

上面创建线程的基本流程是:
使用threading.Thread()创建一个对象,并且在使用target来指定一个函数,作为线程要执行的代码

  • 示例代码
import threading
import time

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


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

封装性更好的一种创建线程的方式是:
定义一个新的类,继承Thread类
在这个类中实现run方法
在run方法中写如要执行的代码
当使用这个类创建一个对象后,调用对象的start方法就可以让这个线程执行,且会自动执行run方法的代码

队列(Queue)
  • 什么是队列

一种特殊的存储数据的方式,可以实现先存入的数据,先出去。

  • 代码演示
import queue

q = queue.Queue()
q.put('11')  # 存入字符串
q.put(22)  # 存入整数
q.put({'num': 100})  # 存入字典

print(q.get())  # 11
print(q.get())  # 22
print(q.get())  # {'num': 100}
  • 总结

先进先出(FIFO)
可以存放任意类型数据

  • 堆栈Queue
import queue
q = queue.LifoQueue()
q.put('11')  # 存入字符串
q.put(22)  # 存入整数
q.put({'num': 100})  # 存入字典

print(q.get())  # {'num': 100}
print(q.get())  # 22
print(q.get())  # 11
  • 总结

后进先出(LIFO)
可以存放任意数据类型

  • 优先级Queue
import queue

q = queue.PriorityQueue()
q.put((10, 'Q'))
q.put((30, 'Z'))
q.put((20, 'A'))

print(q.get())  # (10, 'Q')
print(q.get())  # (20, 'A')
print(q.get())  # (30, 'Z')
  • 总结

存放的数据是元组类型,第1个元素表示优先级,第2个元素表示存储的数据
优先级数字越小优先级越高
数据优先级高的优先被取出
用于VIP用户数据优先被取出场景,因为上面两种都要挨个取出

多线程的优缺点

优点:
在一个进程内的所有线程共享全局变量,很方便在多个线程间共享数据
缺点:
线程是对全局变量随意遂改可能造成多线程之间对全局变量的混乱(即线程非安全)
如果多个线程同时对同一个全局变量操作,会出现资源竞争问题,从而数据结果会不正确

互斥锁

为什么要用互斥锁

当多个线程几乎同时修改某一个共享数据的时候,需要进行同步控制
线程同步能够保证多个线程安全访问竞争资源,最简单的同步机制是引入互斥锁。

互斥锁的作用

互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性。

  • 使用互斥锁

threading模块中定义了Lock类,可以方便的使用:

# 创建锁
mutex = threading.Lock()

# 锁定
mutex.acquire()

# 释放
mutex.release()

锁的好处:
确保了某段关键代码同时只能由一个线程从头到尾完整地执行
锁的坏处:
阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了
由于可以存在多个锁,不同的线程持有不同的锁,并试图获取对方持有的锁时,可能会造成死锁

进程

  • 什么是进程

一个程序运行起来后,代码+用到的资源 称之为进程,它是操作系统分配资源的基本单元。

  • 实现多任务

在python中使用使用进程实现多任务的方式有3种:
1.创建Process对象
2.基础Process类,创建自己的对象,实现run翻番
3.使用进程池

  • 创建进程方式1
from multiprocessing import Process
import time
 
def test():
    """子进程单独执行的代码"""
    while True:
        print('---test---')
        time.sleep(1)
 
if __name__ == '__main__':
    p=Process(target=test)
    p.start()
    # 主进程单独执行的代码
    while True:
        print('---main---')
        time.sleep(1)

每个进程都有1个数字来标记,这个数字称之为进程号
Linux系统中查看PID的命令是ps

  • Process创建的实例对象的常用方法:

start():启动子进程实例(创建子进程)
is_alive():判断子进程是否还在活着
join([timeout]):是否等待子进程执行结束,或等待多少秒
terminate():不管任务是否完成,立即终止子进程

  • 且, 进程不同享全局变量

进程、线程对比

  • 通俗理解进程、线程

进程,能够完成多任务,比如 在一台电脑上能够同时运行多个QQ
线程,能够完成多任务,比如 一个QQ中的多个聊天窗口

  • 区别:

一个程序至少有一个进程,一个进程至少有一个线程.
线程的划分尺度小于进程(资源比进程少),使得多线程程序的并发性高。
进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率
线线程不能够独立执行,必须依存在进程中

优缺点
线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源的管理和保护;而进程正相反。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值