python线程、进程、协程介绍

                            线 程
并发: 任务数大于cpu的核数叫并发,多个任务交替执行, 并发看起来是一起运行其实是一个假象。
并行: 任务数小于或者等于cpu的核数并行,并行才能真正意义上多个任务一起运行
1.import threading:调用功能可创建线程
2.threading.Thread(target=show_info, name="mythread",args = () ,kwargs={}):创建线程
  2.1 group: 线程组,默认值是None,目前只能使用None值
  2.2 target: 执行目标的函数
  2.3 name: 线程名, 默认起名字类似与: Thread-1, ....
  2.4 args:以元组的方式给函数传参
  2.5 kwargs: 以字典的方式给函数传参
3.threading.current_thread():扩展: -获取当前代码执行的线程对象
4.threading.enumerate():获取当前程序活动线程的列表
5.子线程.setDaemon(True):表示守住主线程, 主线程退出子线程直接销毁不再执行代码
6.创建自定义线程就是创建一个类,再创建一个对象,然后对象.start()
7.子线程.join():让主线程等待写入线程执行完成以后程序再退出,线程同步,按照预定的顺序去执行代码,一个任务执行完成以后另外一个任务才能执行
8.lock = threading.Lock():创建锁
  8.1 lock.acquire():上锁
  8.2 lock.release():释放锁
  8.3 互斥锁
    8.3.1 保证同一时刻只有一个线程去执行代码,其它线程没有抢到锁会等待
    8.3.2 提示:加上互斥锁,那个线程抢到锁我们绝对不了因为,线程执行是无序
    8.3.3 注意点: 线程同步和加上互斥锁把多任务瞬间该成单任务,性能会下降


                            进 程
1. 进程:通俗理解一个运行起来的程序或者软件叫做进程
  1.1 每次启动一个进程都想操作系统索要运行资源,进程是操作系统资源分配的基本单位
  1.2 默认情况下启动一个进程默认只有一条线程,这个线程主线程, 线程是依附在进程里面的,没

  有进程就没有线程,进程可以有多个线程
  1.3 如何理解进程:可以把进程想成公司,公司会给员工提供办公资源(办公电脑,办公桌椅等资

  源), 真正干活的是员工, 公司好比进程,员工线程
2. 进程和线程的对比
  2.1 进程: 每次启动一个进程都需要向操作系统索要运行资源,进程是操作系统资源分配的基本单

  位
  2.2 线程: 执行代码的分支,线程是cpu调度的基本单位, 线程是依附在进程里面的,没有进程就

  没有线程,默认一个进程只有一个线程,但是可以开辟多个线程
  2.3 进程不共享全局变量, 线程共享全局变量但是要注意资源竞争数据错误的问题, 可以使用线

  程同步或者互斥锁
  2.4 多进程开发比单进程多线程开发稳定性要强, 因为某个进程死了不会影响其它进程的运行,但

  是单进程多线程开发,如果这个进程死了,那么进程中的所有线程都不能再运行了
  2.5 多进程开发比单进程开发资源要分配的多,多线程可以利用进程中的资源,但是每次启动一个

  进程都需要向操作系统索要运行资源
3. import multiprocessing:调用功能可创建进程
4. 子线程.pid:扩展-获取当前进程的编号
5. multiprocessing.Process(group=None, target=show_info, name="myprocess", args=("小明", 20)):创建子进程
  5.1 group:进程组,默认值是None,目前只能使用None不能设置其它参数
  5.2 target: 执行目标函数
  5.3 name: 进程名称,默认的格式: Process-1,....
  5.4 args: 以元组方式传参
  5.5 kwargs: 以字典方式传参
6. 子进程.start():启动子进程,执行对应的任务
7. 子进程.pidos.getpid():都是获取子进程编号
8. os.getppid():获取父进程(主进程)编号
9. os.kill(os.getpid(), 9):# 扩展-根据进程编号杀死对应的进程,os.getpid()进程编号,9表示强制杀死
10. 子进程.join():主进程等待写入进程执行完成以后程序再往下继续执行
11. 子进程.daemon = True:设置守护主进程, 主进程退出后子进程直接销毁了。
12. 子进程.terminate():让子进程直接销毁
13. queue = multiprocessing.Queue(3):# 创建消息队列,3表示消息队列最大个数
  13.1 queue.put(' '):向变量名里面传输数据,队列满了在放入数据, 就不能放入数据了,直到消息

  队列有空闲位置才能再放入数据
  13.2 queue.put_nowait:不会等待队列有空闲位置再放入数据,如果数据放入不成功就直接崩

  溃。建议: 放入数据使用put,因为比较安全不会崩溃

  13.3 queue.full():查看队列是否是满的。坑点: 只使用put放入数据直接判断队列是否为空获取的

  结果不正确,因为没有等队列把数据写完直接就取获取了,那么这是队列是空的

  13.4 queue.qsize():得到队列里面数据的个数,mac 版本不能使用qsize()
  13.5 queue.empty():判断队列是否为空,空得到True,有数据得到Flase
  13.6 queue.get():获取队列的数据,队列为空,使用get会等待,直到队列有数据以后再取值
  13.7 queue.get_nowait():队列为空,取值的时候不等待,但是取不到值那么直接崩溃了。建

  议:获取队列的数据统一get,因为能保证代码不会有问题

14. multiprocessing.Pool(3):创建进程池 3: 进程池中进程的最大个数。注:进程池:,池子里面放的都是进程,进程的创建有进程池负责,执行任务的时候循环利用指定进程大小个数执行对应的任务
  14.1 apply():表示同步执行,表示一个任务执行完成另外一个任务才能执行
  14.2 apply_async():表示异步执行,异步是不会等待其它任务执行完成以后再去执行,多个任务一

  起执行
  14.3 pool.close():关闭进程池,不再接收其它任务
  14.4 pool.join():主进程等待进程池执行完成以后再退出
15 queue = multiprocessing.Manager().Queue():创建进程池的queue
                            协 程
协程:又称为微线程,也可以说成用户级线程, 在不开辟线程的基础上可以完成多任务
如何理解协程: 只要在def里面只看到一个yield关键字表示就是协程
学习协程目的: 在单线程的基础上可以完成多任务,多个任务按照一定顺序交替执行
迭代:使用for循环遍历取值的过程就叫做迭代。可迭代对象有: 元组,列表,字典,字符串,集合,range;int对象不是可迭代对象
1.from collections import Iterable : 可迭代类型k,
2.isinstance((3, 5), Iterable):判定(3,5)是不是可迭代类型。扩展:-以后可以通过isinstance判断函数的参数或者方法的参数是否是指定类型,(3, 5)判定的对象,Iterable判定的类型
2.自定义可迭代对象
  2.1 在类里面提供了__iter__方法创建的对象就是可迭代对象。
  2.2 自定义迭代器对象: 在类里面提供__iter____next__的方法创建的对象就是迭代器对象
  2.3 迭代器的作用: 记录当前数据的位置以后获取下一个位置的值
  2.4 总结: 可迭代对象的本质:通过迭代器依次获取对象中的数据需要返回一个迭代器
  2.5 使用for遍历可迭代对象依次获取对应的数据
  2.6 扩展 raise StopIteration表示越界,抛出停止迭代的异常信息
3. iter函数:获取可迭代对象的迭代器, 会调用可迭代对象身上的__iter__方法
4. next函数:获取迭代器中下一个值,会调用迭代器对象身上的__next__方法
5.iter获取可迭代对象.的迭代器,得到的是<__main__.StudentIterator object at 0x00000000027A7828>
6.生成器: 是一个特殊的迭代器,也就是说生成器依然可以使用next函数和for循环遍历取值
  6.1创建生成器方式1:my_generator = (i * 2 for i in range(10)) 创建生成器后for来遍历得到结果
  6.2创建生成器2:使用yield,只要在def里面看到yield表示生成器。代码执行yield会暂停,把结果返

  回给外界,再次启动生成器会在暂停的位置继续往下执行
  6.3代码执行到return关键字的时候会抛出停止迭代的异常,后面就是有数据也不会取了;生成器里

  面使用return关键字语法上没有问题,但是注意代码执行到return关键字会抛出停止迭代的异

  常;python3执行return, python2不支持。
  6.4 yield每次启动生成器yield都会返回一个值,也就是说多次启动生成器可以返回多次值;return

  只会返回一次值,并且抛出停止迭代异常,获取返回值通过捕获异常取到返回值
7.调用生成器的send方法
  7.1可以根据参数判断是否可以停止迭代,执行return关键字就可以停止
  7.2总结: send可以给生成器传参数,但是第一次启动生成器只能传None,一般第一次启动生成器

  使用next函数
8.greenlet: 为了更好的让程序员使用协程可以使用greenlet,因为greent封装的yield
  8.1 变量名 = greenlet.greenlet(所执行的任务名):创建协程执行对应的任务
  8.2 变量名.switch():切换到第一个协程执行对应的任务
9.from gevent import monkey
  9.1 monkey.patch_all():需要打补丁,让gevent能够识别系统的耗时操作及网络延时操作
10. import gevent:gevent框架封装Greenlet,会根据耗时操作自动完成协程之间的切换执行
  10.1 pip3 install gevent :下载gevent
  10.2 变量名 = gevent.spawn(所执行的任务名):创建协程完成对应的任务
  10.3 变量名 .join():让主线程等待协程执行完成以后程序再退出
11. import urllib.request : 导入网络请求模块
11.1 urllib.request.urlopen():根据图片地址加载网络资源数据
11.2 gevent.spawn(download_img, img_url1, "1.jpg"):创建协程对象指定对应的任务
  11.2.1 函数名,
  11.2.2 函数对应的参数1: img_url1
  11.2.3 函数对应的参数2: 图片名
                           进程、线程、协程对比
1. 先有进程,然后进程里面可以创建多个线程,线程里面可以有多个协程
2. 进程之间不共享全局变量,线程之间共享全局变量,但是要注意资源竞争的问题
3. 多进程开发比单进程多线程开发稳定性要强,但是多进程开发比多线程开发资源开销要大
4. 线程之间执行时无序的,但是协程在不开辟线程的基础上可以完成多任务,多个任务按照一定顺序交替执行
5. 协程以后主要用在网络爬虫,网络请求,每开辟协程大概需要5k空间
6. 开辟一个线程大概需要512k空间,进程需要资源更多

猜你喜欢

转载自www.cnblogs.com/xmh1023/p/9105914.html