美文网首页
并发编程-协程

并发编程-协程

作者: Yanl__ | 来源:发表于2019-10-29 21:37 被阅读0次
  1. 协程
    • greenlet模块 (gevent实现原理)
    • gevent模块 (注册协程,实现异步编程)
  2. 协程的应用
    eg:爬虫、socket聊天

协程

  1. 概念

    • 能够在一个线程中实现并发效果。
    • 能够规避一些任务中的IO操作,在检测到IO就切换到其他任务
  2. 对比进程和线程

    • 进程和线程的任务切换由操作系统完成
    • 协程任务之间的切换由程序(代码)完成,只有遇到协程模块能识别的IO操作的时候,程序才会进行任务切换,实现并发的效果
    • 进程、线程、协程的开启数量:
      cpu核心数:4
      进程 开5个 (cpu数+1)
      线程 开20个 (进程数4)
      协程 开5w个 (进程数
      线程数*500)一个线程能开500个协程

greenlet模块

真正的协程模块就是使用greenlet完成切换的

# 多任务之间切换的方法 greenlet模块   (协程)
from greenlet import greenlet
def eat():
    print('eating start')
    g2.switch()  # 切换到对应的方法,接着执行 
    print('eating end')


def play():
    print('playing start')

g2 = greenlet(play)
g1 = greenlet(eat)
g1.switch()

gevent模块

  • gevent 感知不到其他模块(time或其他阻塞)的阻塞。只能用gevent.sleep()
  • 不过可以通过打补丁实现感知time 、 socket的阻塞 from gevent import monkey;monkey.patch_all() 此行代码需要放在文件的开头,在import time之前
gevent方法:
  1. g1 = gevent.spawn(func)将func注册到协程 spawn(func, *args, **kwargs)
  2. g1.join()激活协程,等待g1结束
  3. g1.value拿到协程对象的返回值(就是协程执行的func的返回值)
  4. gevent.joinall(iterator) 将多个协程对象保存为一个可迭代对象,传入joinall方法,等待所有协程结束
import gevent
def eat():
    print('eating start')
    gevent.sleep(2)  # gevent 感知不到其他模块(time或其他阻塞)的阻塞。只能用gevent.sleep()
    # 不过可以通过打补丁实现感知time 、 socket的阻塞  from gevent import monkey;monkey.patch_all()
    print('eating end')

def play():
    print('playing start')
    gevent.sleep(2)
    print('playing end')

g1 = gevent.spawn(eat)  # 将func注册在协程中
g2 = gevent.spawn(play)
g1.join()  # 等待协程执行完毕
g2.join()
from gevent import monkey;monkey.patch_all()
import time
import gevent
def eat(i):
    print('eating start')
    time.sleep(2)  # gevent 感知不到其他模块(time或其他阻塞)的阻塞。只能用gevent.sleep()
    # 不过可以通过打补丁实现感知time 、 socket的阻塞  from gevent import monkey:monkey.patch_all()
    print('eating end')
    return '%send'%i

def play():
    print('playing start')
    time.sleep(2)
    print('playing end')

g_list = []
ge_list = []
for i in range(10):
    ge = gevent.spawn(play)
    ge_list.append(ge)

for i in range(20):
    g = gevent.spawn(eat, i)
    g_list.append(g)

for ge in ge_list:            # 等待所有协程执行完毕的 方法一
    ge.join() 
gevent.joinall(g_list)        # 等待所有协程执行完毕的 方法二

for g in g_list:
    print(g.value)  # 获得func的返回值

协程的应用

爬虫

获取网页内容

方法一:requests
import requests
def get_content(url):
    content = requests.get(url)        # 通过request.get到的网页内容是无格式的
    return content.content.decode('utf-8')

url = 'http://www.baidu.com'
print(get_content(url))

方法二:urlopen
from urllib.request import urlopen
def get_content(url):
    content = urlopen(url)        # urlopen到的网页内容是有格式的
    return content.read().decode('utf-8')

url = 'http://www.baidu.com'
print(get_content(url))

协程来爬取网页

from gevent import monkey;monkey.patch_all()
import gevent
import ssl
from urllib.request import urlopen, Request
def get_content(url):
    context = ssl._create_unverified_context()
    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101 Firefox/23.0'}
    get_url = Request(url=url, headers=headers)
    content = urlopen(get_url, context=context)        # urlopen到的网页内容是有格式的
    text = content.read().decode('utf-8')
    return len(text)

url_list = ['http://www.baidu.com',
            'http://www.jianshu.com',
            'http://www.csdn.com',
            'http://www.cctv.com',
            'http://www.sogou.com']
# 通过协程来并发获得网页内容的长度
g_list = []
for i in range(len(url_list)):
    g = gevent.spawn(get_content, url_list[i])
    g_list.append(g)
for g in g_list:g.join()
for g in g_list:print(g.value)

socket

server端

from gevent import monkey;monkey.patch_all()
import gevent
import socket
sk = socket.socket()
sk.bind(('127.0.0.1', 8080))
sk.listen()

def talk(conn):
    conn.send(b'hello')
    msg = conn.recv(1024).decode('utf-8')
    print(msg)
    conn.close()


while True:
    conn, addr = sk.accept()
    gevent.spawn(talk, conn)


sk.close()

client端

import socket
sk = socket.socket()
sk.connect(('127.0.0.1', 8080))

msg = sk.recv(1024).decode('utf-8')
print(msg)
send_msg = input('>>>')
sk.send(send_msg.encode('utf-8'))
sk.close()

相关文章

  • 第六天

    一、并发编程 并发与并行(并发时间片轮询)资源竞争 1、goruntine协程 主协程退出了其他协程也跟着退出 主...

  • Go 并发编程:Goroutine常见应用范式

    一、多独立协程并发——worker分工模式 并发协程独立运行且互不通信,主协程等待处理独立子协程的结果 并发编程有...

  • Kotlin 并发编程之"协程"

    Kotlin 并发编程之"协程" Kotlin协程简介 Kotlin, as a language, provid...

  • 36.Python并发编程之协程

    Python并发编程之协程 协程协程是程序级别的概念,操作系统根本就没有协程的概念!!!协程的本质就是一条线程,可...

  • 并发编程-协程

    协程greenlet模块 (gevent实现原理)gevent模块 (注册协程,实现异步编程) 协程的应用eg:...

  • Gevent高并发网络库精解

    进程 线程 协程 异步 并发编程(不是并行)目前有四种方式:多进程、多线程、协程和异步。 多进程编程在python...

  • 协程小实验

    协程(Coroutine)是目前比较流行的一种并发编程模型,在主流的编程语言里都能找到协程的实现,比如libtas...

  • Gevent

    前述 进程 线程 协程 异步 并发编程(不是并行)目前有四种方式:多进程、多线程、协程和异步。 多进程编程在pyt...

  • Gevent简明教程

    前述 进程 线程 协程 异步 并发编程(不是并行)目前有四种方式:多进程、多线程、协程和异步。 多进程编程在pyt...

  • 第二章 Goroutine泄漏的调试

    在我们谈论协程(Goroutines)泄漏之前,我们先看看并发编程的概念。并发编程处理程序的并发执行。多个连续流任...

网友评论

      本文标题:并发编程-协程

      本文链接:https://www.haomeiwen.com/subject/awjwvctx.html