python进程、线程、协程

一. 进程和线程
进程是资源分配的单位。当开启一个程序便创建了一个进程。各进程之间相互独立。每一个程序至少要有一个进程,每一个进程至少要有一个线程
线程是CPU调度的最小单位。各个线程除了拥有一些必需的资源外,会共享进程的资源。进程可以理解为一个公司,拥有很多资源,比如,办公室,桌椅等。而线程可以理解为公司内的员工,可以分配去执行工作任务。

二.python中创建多线程的方式
当没有创建多线程时,程序只能按照一定的顺序一步一步执行。按照下述例子,先执行fun函数,再接着向下执行。

def fun():
    for i in range(10):
        print("fun函数", i, end=" ")


if __name__ == "__main__":
    fun()
    for i in range(10):
        print("main", i, end=" ")

执行结果为:

fun函数 0 fun函数 1 fun函数 2 fun函数 3 fun函数 4 fun函数 5 fun函数 6 fun函数 7 fun函数 8 fun函数 9 main 0 main 1 main 2 main 3 main 4 main 5 main 6 main 7 main 8 main 9 

当使用多线程时,程序会并发执行

  • 利用threading里的Thread模块
    注意:此时程序中i的范围如果还是10的话,因为执行速度很快,所以看不出效果。这里改为1000,就能够看到他们是异步执行的。
from threading import Thread
def fun():
    for i in range(1000):
        print("fun函数", i)


if __name__ == "__main__":
    t = Thread(target=fun)     # 创建了一个线程
    t.start()                  # 可以开始执行该线程
    for i in range(1000):
        print("main", i)
  • 重写Thread模块中的run函数
    注意:虽然重写了run函数,但是开始运行的时候还是使用start
from threading import Thread

class MyThread(Thread):    # 定义一个类继承Thread
    def run(self):
        for i in range(1000):
            print("子线程", i)


if __name__ == "__main__":
    t = MyThread()             # 创建实例化对象
    t.start()                  # 可以开始执行该线程
    for i in range(1000):
        print("main", i)

如果想给函数传参以区分不同线程执行的同一个函数,可以使用以下形式
注意:传递参数必须是元组

from threading import Thread
def fun(name):
    for i in range(1000):
        print(name, i)


if __name__ == "__main__":
    t1 = Thread(target=fun, args=("周杰伦",))     # 传递参数必须是元组
    t1.start()                  # 可以开始执行该线程
    t2 = Thread(target=fun, args=("王力宏",))
    t2.start()

三. 多进程
多进程和多线程创建方法相似。开进程比较耗费资源,一般不使用。

from multiprocessing import Process


def fun():
    for i in range(1000):
        print("子进程", i)


if __name__ == "__main__":
    p = Process(target=fun)
    p.start()
    for i in range(1000):
        print("主进程",i)

四.线程池

线程池:一次性开辟一些线程,用户直接给线程池子提交任务。线程任务的调度交给线程池来完成。如下代码开辟了一个线程数为50的线程池。提交100次任务。

from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor

def fn(name):
    for i in range(1000):
        print(name, i)


if __name__ == "__main__":
    # 创建线程池
    with ThreadPoolExecutor(50) as t:
        for i in range(100):
            t.submit(fn, name=f"线程{i}")
    # 等待线程池中的任务全部执行完毕再执行
    print("123")

如果要用进程池,将ThreadPoolExecutor换成ProcessPoolExecutor

五.协程
当遇到某些操作时,程序会处于阻塞状态。如:
sleep(3) 强制等待
input() 等待输入
request.get() 网络请求返回数据之前,阻塞
故一般情况下,当程序处于IO操作的时候,线程都会处于阻塞状态

在单线程条件下:
协程:当程序遇见IO操作,可以选择性的切换到其他任务上。
在微观上是一个任务一个任务的进行切换,切换条件是IO操作
在宏观上,我们能看到的其实是多个任务一起在执行——多任务异步操作
注意:如果使用time.sleep,则运行程序,耗时9s多,异步操作并没有起到作用。当程序出现了同步操作的时候,异步就中断了
需要将time.sleep换为await asyncio.sleep(),此时运行耗费4s多

import asyncio
import time


async def func1():
    print("你好啊,我叫塞里亚")
    # time.sleep(3)           # 当程序出现了同步操作的时候,异步就中断了
    await asyncio.sleep(3)
    print("你好啊,我叫塞里亚")


async def func2():
    print("你好啊,我叫周杰伦")
    # time.sleep(3)                # 当程序出现了同步操作的时候,异步就中断了
    await asyncio.sleep(3)          # 异步操作代码
    print("你好啊,我叫周杰伦")


async def func3():
    print("你好啊,我叫张三")
    # time.sleep(3)
    await asyncio.sleep(3)
    print("你好啊,我叫张三")


async def main():
    # 第一种写法
    # f1 = func1()
    # await f1   # 一般await挂起操作放在协程对象前面
    # 第二种写法(推荐)
    tasks = [
    	asyncio.create_task(func1()), 
    	asyncio.create_task(func2()), 
    	asyncio.create_task(func3())] 
    	# python3.8以后需要加上asyncio.create_task
    await asyncio.wait(tasks)

if __name__ == "__main__":
    t1 = time.time()
    asyncio.run(main())
    t2 = time.time()
    print(t2-t1)

使用requests.get()时,需要将同步代码变为异步操作。需要用到aiohttp
安装
pip install aiohttp

s = aiohtto.ClientSession() 等价于 requests
接着正常使用s.get() s.post()

下载图片的函数代码

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值