第四十一天:协程操作

1.无论是进程还是线程都是由操作系统的时间片时间来进行操控,无法进行人为的控制,并且进行的都是并发程序。从微观上看还是同一时间执行一个程序。

2.进程是资源分配的最小单位,线程是cpu调度的最小单位。在开启线程的过程中,创建一个线程需要创建一个寄存器和堆栈,这些都是要花费时间的。

3。协程操作:为了实现并发操作:主要是为了多个任务之间进行切换。

4.以前学的生产者消费者模型里就含有这种模式的模型:

def consumer():
    while True:
        x=yield
        print(‘处理了数据‘,x)
def production():
    c=consumer()
    next(c)
    for i in range(10):
        print(‘生产了数‘,i)
        c.send(i)
production()

5.装greenlet模块:打开cmd然后输入C:——enter——输入pip install greenlet 就可以下载了

6.安装gevent:步骤和上面一样就是输入 pip install  gevent

7.协程的第一个列子:

from greenlet import greenlet
import time
def eat():
    print(‘eat start‘)
    time.sleep(1)
    print(‘eat end‘)
def play():
    print(‘play start‘)
    time.sleep(1)
    print(‘play end‘)
g1=greenlet(eat)#只是进行实例化,并没有执行该函数
g2=greenlet(play)

从结果可以看出没有执行任何指令:

8.使用switch才能执行函数里的指令(此语句代表的意思是切换)

from greenlet import greenlet
import time
def eat():
    print(‘eat start‘)
    time.sleep(1)
    g2.switch()#记住执行的位置,并切换到play去执行
    print(‘eat end‘)
def play():
    print(‘play start‘)
    time.sleep(1)
    g1.switch()#记住执行的位置,并切换到play去执行
    print(‘play end‘)
g1=greenlet(eat)#只是进行实例化,并没有执行该函数
g2=greenlet(play)
g1.switch()#切换到eat函数去执行
结果为
eat start
play start
eat end

从结果可以看出切换到eat执行完成之后并由切换到play执行最后的语句,使用的解决方法是:

9.计算时间执行和协程切换执行花费的时间:

  顺序执行的时间:

import time
from greenlet import greenlet
def func():
    for i in range(10000000):
        i*i
def func1():
    for i in range(10000000):
        i+i
start=time.time()
func()
func1()
t1=time.time()-start
print(t1)
结果为
1.0864977836608887

  使用协程操作的时间

import time
from greenlet import greenlet
def func():
    for i in range(10000000):
        i*i
        g2.switch()
def func1():
    for i in range(10000000):
        i+i
        g1.switch()
start=time.time()
g1=greenlet(func)
g2=greenlet(func1)
g1.switch()
g2.switch()
t1=time.time()-start
print(t1)
结果为
5.035648822784424

从两个结果可以看出每次协程之间的转换是要花费时间的。

10.协程主要用于高IO操作中,当程序在执行过程中如果遇到IO操作,就会进入堵塞状态,程序无法进行下面的流程,如果把这个时间空出来供另一个协程使用,这样就提高了资源的利用率

11.一般来说进程一般为cpu个数+1 线程为cpu个数的5倍,协程一般最多开500个

12.虽然协程在切换期间会浪费时间,但是浪费的时间远远小于堵塞的时间。

13.协程的第个操作指令:gevent

g1=gevent.spawn(func,参数)创建一个协程对象g1,spawn括号内第一个参数是函数名
后面的可以是位置参数也可以是关键字参数。
g1.join()  #等待g1的结束
g2.join()
或者使用gevent.joinall([g1,g2])
g1.value 拿到返回值

14.可以使用from gevent import monkey;monkey.patch_all(),把所有可以发生堵塞的模块进行打包,并且此模块一定要放到所有导入模块的最前面

from gevent import monkey;monkey.patch_all()
import gevent
import time
def eat():
    print(‘eat start‘)
    time.sleep(1)
    print(‘eat end‘)
def play():
    print(‘play start‘)
    time.sleep(1)
    print(‘play end‘)
g1=gevent.spawn(eat)
g2=gevent.spawn(play)
g1.join()
g2.join()
结果为
eat start
play start
eat end
play end

15。协程的执行是否依靠join操作

from gevent import monkey;monkey.patch_all()
import gevent
import time
def eat():
    print(‘eat start‘)
    time.sleep(1)
    print(‘eat end‘)
def play():
    print(‘play start‘)
    time.sleep(1)
    print(‘play end‘)
g1=gevent.spawn(eat)
g2=gevent.spawn(play)
g1.join()

从结果我们可以看出只有启动一个协程就可以执行所有实例化的协程

16.协程里面的任务切换是通过greenlet中的switch进行的。

17进程和线程里的切换操作都是由操作系统控制完成的,而协程里的切换操作是由程序操作的(代码)。

18只有遇到高要求的IO操作时,我们才使用协程操作,实行并发的效果。

19.查看协程号的程序:

from gevent import monkey;monkey.patch_all()
import gevent
import time
import threading
def eat():
    print(‘eat start‘)
    print(threading.current_thread(),threading.get_ident)
    time.sleep(1)
    print(‘eat end‘)
def play():
    print(‘play start‘)
    print(threading.current_thread(),threading.get_ident)
    time.sleep(1)
    print(‘play end‘)
g1=gevent.spawn(eat)
g2=gevent.spawn(play)
g1.join()
结果为
eat start
<_DummyThread(DummyThread-1, started daemon 1840173395744)> <function get_ident at 0x000001AC72E580D0>
play start
<_DummyThread(DummyThread-2, started daemon 1840177303776)> <function get_ident at 0x000001AC72E580D0>
eat end
play end

从结果来看协程是假的线程,但是两个协程都来自同一个协程。

19.同步和异步的例子(就是使用协程和不使用协程):

from gevent import monkey;monkey.patch_all()
import gevent
import time
import threading
def task():
    time.sleep(1)
    print(1234)
def same():
    for i in range(10):
        task()
def different():
    g_list=[]
    for i in range(10):
        g1=gevent.spawn(task)
        g_list.append(g1)
    gevent.joinall(g_list)
same()
different()

从结果来看,同步是一个一个执行,异步是一次性输出所有接过执行原理是,当遇到sleep时,程序进入堵塞,协程这个时候就会切换到下面一次程序进行,然后继续堵塞,继续切换,等到哪个程序执行完成后再进行切换,切换过来以后,那写程序sleep时间都到了,所以可以实现并发的效果。

20.协程主要是能够在一个线程中实现并发效果。能够规避一些任务中的IO操作‘在任务执行的过程当中,检测到IO操作就可以切换到其他任务去执行。

21.协程的操作主要应用与爬虫和请求IO的等待。

22.爬虫的小例子:

from gevent import monkey;monkey.patch_all()
import gevent
import time
import requests
def acquire_url(url):
    ret=requests.get(url)
    ret=ret.content.decode(‘utf-8‘)
    return len(ret)
g1=gevent.spawn(acquire_url,‘http://www.baidu.com‘)
g2=gevent.spawn(acquire_url,‘http://www.sougou.com‘)
g3=gevent.spawn(acquire_url,‘https://cn.bing.com/?mkt=zh-CN&mkt=zh-CN&mkt=zh-CN‘)
g4=gevent.spawn(acquire_url,‘https://www.sohu.com/‘)
g5=gevent.spawn(acquire_url,‘https://www.so.com/‘)
gevent.joinall([g1,g2,g3,g4,g5])
print(g1.value)
print(g2.value)
print(g3.value)
print(g4.value)
print(g5.value)

23使用协程来写socket的程序:

server端程序:

from gevent import monkey;monkey.patch_all()
import socket
import gevent
def connection(conn):
    conn.send(‘你好‘.encode(‘utf-8‘))
    msg=conn.recv(1024).decode(‘utf-8‘)
    print(msg)

sk=socket.socket()
sk.bind((‘127.0.0.1‘,8080))
sk.listen()
while True:
    conn,addr=sk.accept()
    g1=gevent.spawn(connection,conn)

  client端程序:

import socket
sk=socket.socket()
sk.connect((‘127.0.0.1‘,8080))
while True:
    msg=sk.recv(1024).decode(‘utf-8‘)
    print(msg)
    info=input(‘请输入信息‘).encode(‘utf-8‘)
    sk.send(info)

协程执行的过程就是把每一次获取到的结果放到一片空间中,等遇到堵塞了再去执行下一个协程。

原文地址:https://www.cnblogs.com/ab461087603/p/12532024.html

时间: 2024-08-27 20:01:58

第四十一天:协程操作的相关文章

flask多线程多协程操作

local的作用:各个线程各开辟一块空间互不影响 基于local""" import threading from threading import local import time obj = local() def task(i): obj.xxxxx = i time.sleep(2) print(obj.xxxxx,i) for i in range(10): t = threading.Thread(target=task,args=(i,)) t.start()

python之协程与IO操作

协程 协程,又称微线程,纤程.英文名Coroutine. 协程的概念很早就提出来了,但直到最近几年才在某些语言(如Lua)中得到广泛应用. 子程序,或者称为函数,在所有语言中都是层级调用,比如A调用B,B在执行过程中又调用了C,C执行完毕返回,B执行完毕返回,最后是A执行完毕. 所以子程序调用是通过栈实现的,一个线程就是执行一个子程序. 子程序调用总是一个入口,一次返回,调用顺序是明确的.而协程的调用和子程序不同. 协程看上去也是子程序,但执行过程中,在子程序内部可中断,然后转而执行别的子程序,

python2.0_s12_day9_协程&amp;Gevent协程

Python之路,Day9 - 异步IO\数据库\队列\缓存 本节内容 Gevent协程 Select\Poll\Epoll异步IO与事件驱动 Python连接Mysql数据库操作 协程 1.协程,又称微线程,纤程.英文名Coroutine.一句话说明什么是协程:协程是一种用户态的轻量级线程.(操作系统跟不知道它存在),那你指定协程的实现原理是什么吗? 我们来聊聊协程的实现原理: 首先我们知道多个线程在一个单核CPU上进行并发,它的操作过程是,操作系统能调动的最小单位是线程,当操作系统触发多个线

python小白-day8 线程、进程、协程

Python线程 线程是操作系统能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务. 1 2 3 4 5 6 7 8 9 10 11 12 13 #!/usr/bin/env python import threading import time def show(arg):     time.sleep(1)     print('thread'+str(arg)) for i

Python开发【第九篇】:协程、异步IO

协程 协程,又称微线程,纤程.英文名Coroutine.一句话说明什么是协程,协程是一种用户态的轻量级线程. 协程拥有自己的寄存器上下文和栈.协程调度切换时,将寄存器上下文和栈保存到其他地方,在切换回来的时候,恢复先前保存的寄存器上下文和栈.因此,协程能保留上一次调用的状态(即所有局部状态的一个特定组合),每次过程重入时,就相当于进入上一次调用的状态,换种说法,进入上一次离开时所处逻辑流的位置. 子程序,或者称为函数,在所有语言中都是层级调用,比如A调用B,B在执行过程中又调用了C,C执行完毕返

python学习笔记-(十四)进程&amp;协程

一. 进程 1. 多进程multiprocessing multiprocessing包是Python中的多进程管理包,是一个跨平台版本的多进程模块.与threading.Thread类似,它可以利用multiprocessing.Process对象来创建一个进程.该进程可以运行在Python程序内部编写的函数.该Process对象与Thread对象的用法类似. 创建一个Process实例,可用start()方法启动. join()方法可以等待子进程结束后再继续往下运行,通常用于进程间的同步.

#协程介绍及基本示例

1 #协程介绍及基本示例 2 3 #Gevent协程(单线程,串行)在线程里启动 4 ''' 5 协程,又称微线程,纤程.英文名Coroutine.一句话说明什么是线程: 6 协程是一种用户态的轻量级线程. 7 8 协程拥有自己的寄存器上下文和栈.协程调度切换时, 9 将寄存器上下文和栈保存到其他地方,在切回来的时候, 10 恢复先前保存的寄存器上下文和栈.因此: 11 12 协程能保留上一次调用时的状态(即所有局部状态的一个特定组合), 13 每次过程重入时,就相当于进入上一次调用的状态,换种

Day9 - 进程、线程、协程篇(二)

本节内容 Gevent协程 Select\Poll\Epoll异步IO与事件驱动 Python连接Mysql数据库操作 RabbitMQ队列 Redis\Memcached缓存 Paramiko SSH Twsited网络框架 协程(单线程下实现多并发的效果) 协程,又称微线程,纤程.英文名Coroutine.一句话说明什么是线程:协程是一种用户态的轻量级线程.(CPU不认识协程,是用户自己操作的) 协程拥有自己的寄存器上下文和栈.协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候

Python之路【第七篇续】:进程、线程、协程

Socket Server模块 SocketServer内部使用 IO多路复用 以及 "多线程" 和 "多进程" ,从而实现并发处理多个客户端请求的Socket服务端.即:每个客户端请求连接到服务器时,Socket服务端都会在服务器是创建一个"线程"或者"进 程" 专门负责处理当前客户端的所有请求. socket server 和 select & epoll 还是不太一样他的本质是:客户端第一次链接的时候,只要一进来