协程

python多协程爬虫示例

谁说我不能喝 提交于 2020-02-26 05:24:50
写python协程时使用gevent模块和queue模块可以大大提高爬虫速度。在同时爬取多个网站时,原来用for循环一个网站一个网站按循序顺序爬,就像先烧饭后烧菜,两个步骤异步进行。使用多协程可以让爬虫自己选择爬取顺序,就像边烧饭边烧菜,两个步骤同步进行,速度自然快了。 不多说了,来看下代码吧: from gevent import monkey monkey.patch_all() #打上多协程布丁,下面的程序就可以执行多协程了 import requests,gevent,csv from gevent.queue import Queue from bs4 import BeautifulSoup #把所有URL都放到一个列表里: url_list=[] i=1 for i in range(10): i=i+1 url='http://www.mtime.com/top/tv/top100/index-'+str(i)+'.html' url_list.append(url) #第一个url和别的不一样,需要单独加入 url_0='http://www.mtime.com/top/tv/top100/' url_list.append(url_0) headers={ 'User-Agent': } csv_file=open('时光网电影列表.csv','a+'

Python并发编程系列之常用概念剖析:并行 串行 并发 同步 异步 阻塞 非阻塞 进程 线程 协程

老子叫甜甜 提交于 2020-02-25 11:13:19
1 引言   并发、并行、串行、同步、异步、阻塞、非阻塞、进程、线程、协程是并发编程中的常见概念,相似却也有却不尽相同,令人头痛,这一篇博文中我们来区分一下这些概念。 2 并发与并行   在解释并发与并行之前,我们必须先明确: 单个处理器(一个单核CPU)在某一个时刻只能处理一个线程 。   并发是指在同一个处理器上通过时间片轮转的方式在多个线程之间频繁切换,由于切换速度极快,所以看似多个线程似乎被同时执行,但实际上每一个时刻都只有一个线程被执行,其他的线程出于阻塞状态。   并行是指多个处理器在同一时刻同时处理了多个不同的线程,这才是真正意义的同时被执行。   如下图所示,线程A与线程B同在一个CPU内执行,且任一t时刻内,都只有一个线程(A或者B)被执行,所以线程A与线程B是并发执行的。线程C和线程D分别在两个CPU内执行,且在某一个t时刻内同时都在执行,所以线程C和线程D是并行的。 3 并行与串行   上面已经说到,并行是指多个任务同时执行,而 串行 是指多个任务时,各个任务按顺序执行,完成一个之后才能进行下一个。   所以,并发与并行是在某一时刻是否都在执行的区别。并行与串行是同时进行或一个结束才进行下一个的区别。 4 同步与异步   同步与异步的概念与消息的通知机制有关:    同步 是指线程在访问某一资源时,获得了资源的返回结果之后才会执行其他操作

Lua的协程和协程库详解

无人久伴 提交于 2020-02-24 03:14:06
转: https://www.cnblogs.com/zrtqsk/p/4374360.html 我们首先介绍一下什么是协程、然后详细介绍一下coroutine库,然后介绍一下协程的简单用法,最后介绍一下协程的复杂用法。 一、协程是什么?   (1)线程   首先复习一下多线程。我们都知道线程——Thread。每一个线程都代表一个执行序列。   当我们在程序中创建多线程的时候,看起来,同一时刻多个线程是同时执行的,不过实质上多个线程是并发的,因为只有一个CPU,所以实质上同一个时刻只有一个线程在执行。   在一个时间片内执行哪个线程是不确定的,我们可以控制线程的优先级,不过真正的线程调度由CPU的调度决定。   (2)协程   那什么是协程呢?协程跟线程都代表一个执行序列。不同的是,协程把线程中不确定的地方尽可能的去掉,执行序列间的切换不再由CPU隐藏的进行,而是由程序显式的进行。   所以,使用协程实现并发,需要多个协程彼此协作。 二、resume和yeild的协作。   resume和yeild的协作是Lua协程的核心。这边用一幅图描述一下,有一个大体的印象。对照下面的coroutine库的详细解释和最后的代码,应该可以搞清楚协程的概念了。   注:这是在非首次resume协程的情况下,resume和yield的互相调用的情况。如果是首次resume协程

协程笔记说明

徘徊边缘 提交于 2020-02-22 16:29:47
协程笔记说明 协程的定义 通过使用yield完成多任务 greenlet进行封装来替换生成器 gevent实现多任务 不依赖gevent的自带延时和阻塞切换 协程和线程差异 进程、线程和协程对比 协程的定义 协程是python个中另外一种实现多任务的方式,只不过比线程更小占用更小执行单元(理解为需要的资源)。 为啥说它是一个执行单元,因为它自带CPU上下文。这样只要在合适的时机, 我们可以把一个协程 切换到另一个协程。 只要这个过程中保存或恢复 CPU上下文那么程序还是可以运行的。 通俗的理解:在一个线程中的某个函数,可以在任何地方保存当前函数的一些临时变量等信息,然后切换到另外一个函数中执行,注意不是通过调用函数的方式做到的,并且切换的次数以及什么时候再切换到原来的函数都由开发者自己确定。 通过使用yield完成多任务 import time def task_1(): while True: print("---1----") time.sleep(0.1) yield def task_2(): while True: print("---2----") time.sleep(0.1) yield def main(): t1 = task_1() t2 = task_2() # 先让t1运行一会,当t1中遇到yield的时候,再返回到t2,然后 # 执行t2

7、线程、进程、协程进阶篇

纵饮孤独 提交于 2020-02-22 15:08:09
1.1.继上一讲,知道了如何创建多线程和GIL的原理,接下来要说的是线程锁,那为什么需要线程锁呢? 先看下图,此图来自:http://www.cnblogs.com/alex3714/articles/5230609.html,我就不自己动手画了,比我画得好 分析: (1)线程1拿到count=0并获得GIL,依次执行1,2,3,4,5,然后执行时间到了释放GIL (2)线程2拿到count=0并获得GIL,依次执行6,7,8,9,10,11,修改count的值,此时count的值由0变成1,并释放GIL (3)线程1再次拿到GIL并继续执行12,13,修改count的值,count的值还是1 问题出现了:线程1和线程2都把count+1,但是最后count的值还是1 线程锁:cpu在执行任务时,在线程之间是进行随机调度的,并且每个线程在执行一段时间之后会切换到另外一个线程,但是由于线程之间堆数据是共享的,所以就会有可能出现上述问题。 没加锁时的代码: # -*- coding: utf-8 -*- #__author:jiangjing #date:2018/2/4 #!/usr/bin/env python # -*- coding:utf-8 -*- import threading import time NUM = 0 def func(): global NUM

进程,线程与协程

て烟熏妆下的殇ゞ 提交于 2020-02-18 22:23:23
进程 一段程序的执行过程,资源分配的基本单位,进程有三种状态,就绪、运行和阻塞.一个程序运行时,系统就会创建一个进程,并为它分配资源,然后把进程放入进程就绪队列(就绪),等到进程调度器选中它时就会为其分配CPU时间,程序开始真正执行(运行),当程序条件不够的时候,需要等待条件满足才能执行(阻塞) 线程 程序执行时的最小执行单元,是进程的执行流,一个进程可以有多个线程组成,线程间共享进程的所有资源,每个线程有自己的堆栈和局部变量. 一个程序至少一个进程,一个进程至少一个线程. 进程线程比较 1.同一进程的线程共享本进程的地址空间,进程之间则是独立的地址空间 2.同一进程内的线程共享本进程的资源(内存,I/O cpu),单进程之间的资源是独立的. 3.线程执行开销小,但一个线程的死掉就等于整个进程死掉;进程比线程健壮,单进程切换时耗费资源较大,效率差 4.线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需要以通信的方式(IPC)进行。不过如何处理好同步与互斥是编写多线程程序的难点。 5.进程是资源分配的最小单位,线程是程序执行的最小单位. 多线程,多进程 均可实现并发.线程快而进程可靠性高 多进程编程,进程之间独立数据空间,数据传递需要依靠通信机制,编程调试简单,可靠性高 但是 创建,销毁,切换速度变慢,内存.资源占用大 多线程 多线程间数据资源贡献

Contiki的内核分析-协程机制(一)

血红的双手。 提交于 2020-02-16 23:33:33
导读 本文通过分析Contiki的源码,梳理Contiki的process-event模型中的process机制。 通过前文的阐述我们贯通了event机制的原理。从本文开始,分析Contiki的process机制。 综述 Contiki的process机制实质上是一种协程调度机制,区别于抢占式调度,它只使用了2个字节的变量保存了process的“栈环境[1]”。所有的process以链表的形式保存。官方对此的称呼是protothread,即轻量级线程。但是协程是对它更好的诠释。在协程的环境下,每个process被动的获得cpu执行权,主动的放弃cpu执行权。因此在编程时务必要小心,防止产生死循环,导致整个系统宕机。 为了完全贯通Contiki中的协程机制,我们需要分为2个方面去阐述它:协程逻辑和协程实现,本篇主要阐述协程的逻辑层面,下篇阐述协程的语法实现层面。 协程运行的预备工作 在旅程的最开始,我们先来看一看Contiki的协程----process的类型定义。删除了一些无关紧要的部分,使代码更简洁。 # define PT_THREAD(name_args) char name_args struct process { //链接域 struct process * next ; //和process绑定的函数指针 PT_THREAD ( ( * thread ) (

深度解密Go语言之context

一个人想着一个人 提交于 2020-02-16 03:23:16
目录 什么是 context 为什么有 context context 底层实现原理 整体概览 接口 Context canceler 结构体 emptyCtx cancelCtx timerCtx valueCtx 如何使用 context 传递共享的数据 取消 goroutine 防止 goroutine 泄漏 context 真的这么好吗 总结 参考资料 Go 语言的 context 包短小精悍,非常适合新手学习。不论是它的源码还是实际使用,都值得投入时间去学习。 这篇文章依然想尝试全面、深入地去研究。文章相比往期而言,整体不长,希望你看完可以有所收获! 什么是 context Go 1.7 标准库引入 context,中文译作“上下文”,准确说它是 goroutine 的上下文,包含 goroutine 的运行状态、环境、现场等信息。 context 主要用来在 goroutine 之间传递上下文信息,包括:取消信号、超时时间、截止时间、k-v 等。 随着 context 包的引入,标准库中很多接口因此加上了 context 参数,例如 database/sql 包。context 几乎成为了并发控制和超时控制的标准做法。 context.Context 类型的值可以协调多个 groutine 中的代码执行“取消”操作,并且可以存储键值对。最重要的是它是并发安全的。

[GO]channel实现数据交互

亡梦爱人 提交于 2020-02-14 19:41:24
package main import ( "fmt" "time" ) func main() { ch := make(chan string)//创建channel defer fmt.Println("主协程也结束了") go func() { defer fmt.Println("子协程调用完毕") for i:=0; i<2; i++ { fmt.Println("子协程i = ", i) time.Sleep(time.Second) } ch <- "我是子协程,我工作完毕" }() str := <-ch//没有数据之前它会一直阻塞这里 fmt.Println("str = ", str) } 执行的结果 子协程i = 0 子协程i = 1 子协程调用完毕 str = 我是子协程,我工作完毕 主协程也结束了 主协程和子协程近乎是同时执行,但是主协程因为有了管道的阻塞所以一直都不会执行打印 子协程在执行过自己的循环之后才会对管道进行一个写值,这时主协程一旦看到管道里有值就会立刻执行下面的程序 来源: https://www.cnblogs.com/baylorqu/p/9673479.html

复习打卡--0826协程、进程池、线程/进程/协程对比

喜夏-厌秋 提交于 2020-02-14 02:17:53
一、协程 协程,又称微线程 协程是python中另外一种实现多任务的方式,只不过比线程更小,占用更小执行单元(理解为需要的资源) 它自带CPU上下文,这样只要在合适的时间,我们就可以把一个协程切换到另一个协程,只要这个过程保存或恢复CPU上下文那么程序还是可以运行的   通俗的理解 在一个线程中的某个函数,可以在任何地方保存当前函数的一些临时变量等信息,然后切换到另外一个函数中执行,注意不是通过调用函数的方式做到的,并且切换的次数以及什么时候再切换到原来的函数都由开发者自己决定   协程和线程差异 在实现多任务时,线程切换从系统层面远不止保存和恢复CPU上下文这么简单,操作系统为了程序的高效性每个线程都有自己缓存Cache等等数据,操作系统还会帮你做这些数据的恢复操作。所以线程的切换比较耗性能。但是协程的切换之间单纯的操作CPU的上下文,所以一秒钟切换个上百万次性能都扛得住。 # 协程的实现: 通过含yield关键字的生成器函数来实现协程 def work1(): for i in range(10): print('---work1获取数据{}'.format(i)) yield i def work2(): for i in range(10) : print('---work2获取数据{}'.format(i)) yield i def main(): g1=work1()