单线程

第三十二章:协程

拈花ヽ惹草 提交于 2020-01-04 05:09:08
引子 上一节中我们知道GIL锁将导致CPython无法利用多核CPU的优势,只能使用单核并发的执行。很明显效率不高,那有什么办法能够提高效率呢? 效率要高只有一个方法就是让这个当前线程尽可能多的占用CPU时间,如何做到? 任务类型可以分为两种 IO密集型 和 计算密集型 对于计算密集型任务而言 ,无需任何操作就能一直占用CPU直到超时为止,没有任何办法能够提高计算密集任务的效率,除非把GIL锁拿掉,让多核CPU并行执行。 对于IO密集型任务任务,一旦线程遇到了IO操作CPU就会立马切换到其他线程,而至于切换到哪个线程,应用程序是无法控制的,这样就导致了效率降低。 如何能提升效率呢?想一想如果可以监测到线程的IO操作时,应用程序自发的切换到其他的计算任务,是不是就可以留住CPU?的确如此 一、单线程实现并发 单线程实现并发这句话乍一听好像在瞎说 首先需要明确并发的定义 并发:指的是多个任务同时发生,看起来好像是同时都在进行 并行:指的是多个任务真正的同时进行 早期的计算机只有一个CPU,既然CPU可以切换线程来实现并发,那么为何不能再线程中切换任务来并发呢? 上面的引子中提到,如果一个线程能够检测IO操作并且将其设置为非阻塞,并自动切换到其他任务就可以提高CPU的利用率,指的就是在单线程下实现并发。 如何能够实现并发呢 并发 = 切换任务+保存状态,只要找到一种方案

python 并发协程

拜拜、爱过 提交于 2020-01-04 05:08:48
一 引子 本节的主题是基于单线程来实现并发,即只用一个主线程(很明显可利用的cpu只有一个)情况下实现并发,为此我们需要先回顾下并发的本质:切换+保存状态 cpu正在运行一个任务,会在两种情况下切走去执行其他的任务(切换由操作系统强制控制),一种情况是该任务发生了阻塞,另外一种情况是该任务计算的时间过长 ps:在介绍进程理论时,提及进程的三种执行状态,而线程才是执行单位,所以也可以将上图理解为线程的三种状态 其中第二种情况并不能提升效率,只是为了让cpu能够雨露均沾,实现看起来所有任务都被“同时”执行的效果,如果多个任务都是纯计算的,这种切换反而会降低效率。为此我们可以基于yield来验证。yield本身就是一种在单线程下可以保存任务运行状态的方法,我们来简单复习一下: #1 yiled可以保存状态,yield的状态保存与操作系统的保存线程状态很像,但是yield是代码级别控制的,更轻量级 #2 send可以把一个函数的结果传给另外一个函数,以此实现单线程内程序之间的切换 单纯地切换反而会降低运行效率 #串行执行 import time def consumer(res): '''任务1:接收数据,处理数据''' pass def producer(): '''任务2:生产数据''' res=[] for i in range(10000000): res.append(i)

day33-2 协程

妖精的绣舞 提交于 2020-01-04 05:07:51
目录 协程 单线程实现并发 greenlet模块实现并发 gevent模块实现并发 协程与线程比较 协程 由于GIL锁导致在Cpython中多线程无法并行执行,只能并发执行。而并发实现的原理是切换+保存,那就意味着使用多线程实现并发,就需要为每一个任务创建一个线程 问题一:必然增加了线程创建销毁与切换带来的资源开销。 问题二:高并发情况下,由于任务数量太多导致无法开启新的线程,使得即没有实际任务要执行,也无法创建新线程来处理新任务的情况 所以应想办法避免创建线程带来的问题,同时又能保证并发效果, 协程就是使用单线程来实现多任务并发 单线程实现并发 并发 = 切换任务+保存状态。python中的生成器就具备这样一个特点,每次调用next都会回到生成器函数中执行代码,并且是基于上一次运行的结果,这就意味着生成器会自动切换任务并保存执行状态 def task1(): while True: yield print('task1 run') def task2(): g = task1() while True: next(g) print('task2 run') task2() 并发虽然实现了,但是效率如何呢? # 两个计算任务:一个采用生成器切换并发执行,一个直接串行调用 import time def task1(): a = 0 for i in range(50000000):

协程

有些话、适合烂在心里 提交于 2020-01-04 05:07:42
引子 上一节中我们知道GIL锁将导致CPython无法利用多核CPU的优势,只能使用单核并发的执行。很明显效率不高,那有什么办法能够提高效率呢? 效率要高只有一个方法就是让这个当前线程尽可能多的占用CPU时间,如何做到? 任务类型可以分为两种 IO密集型 和 计算密集型 对于计算密集型任务而言 ,无需任何操作就能一直占用CPU直到超时为止,没有任何办法能够提高计算密集任务的效率,除非把GIL锁拿掉,让多核CPU并行执行。 对于IO密集型任务任务,一旦线程遇到了IO操作CPU就会立马切换到其他线程,而至于切换到哪个线程,应用程序是无法控制的,这样就导致了效率降低。 如何能提升效率呢?想一想如果可以监测到线程的IO操作时,应用程序自发的切换到其他的计算任务,是不是就可以留住CPU?的确如此 一、单线程实现并发 单线程实现并发这句话乍一听好像在瞎说 首先需要明确并发的定义 并发:指的是多个任务同时发生,看起来好像是同时都在进行 , 实际上是切换 + 记录状态 并行:指的是多个任务真正的同时进行 早期的计算机只有一个CPU,既然CPU可以切换线程来实现并发,那么为何不能在线程中切换任务来并发呢? 上面的引子中提到,如果一个线程能够检测IO操作并且将其设置为非阻塞,并自动切换到其他任务 , 就这样可以提高CPU的利用率,指的就是在单线程下实现并发。 如何能够实现并发呢 ? 并发 = 切换任务

python 端口扫描脚本单线程版

夙愿已清 提交于 2019-12-31 09:15:17
记录下,端口扫描脚本单线程版,刚学python,慢慢来 #!/usr/bin/python3 # coding=utf-8 import socket ip_list = [] rs_list = [] f = open('ip.txt') for each in f.readlines(): tmp_ip = each.replace('\n','') ip_list.append(tmp_ip) f.close() def port_scan(ip): port_list = range(0,65536) for port in port_list: try: s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) s.settimeout(0.1) s.connect((ip,port)) result = str(ip)+":"+str(port)+" OPEN" print(result) rs_list.append(result) s.close() except: pass def main(): for ip in ip_list: port_scan(ip) if __name__=='__main__': main() 来源: CSDN 作者: 梦之履行地 链接: https://blog.csdn.net

开发者都非常熟悉的redis

和自甴很熟 提交于 2019-12-30 01:20:01
说起redis想必每个开发者都非常熟悉,今天就来简单聊聊redis 原文链接地址: https://blog.csdn.net/chenyao1994/article/details/79491337 一文揭秘单线程的Redis为什么这么快? https://zhuanlan.zhihu.com/p/57089960 1.redis的存储结构有哪些? 字符串(String)、散列(Hash)、列表(List)、集合(Set)、有序集合(Zset) redis采用基于内存的单进程单线程模型的kv数据库 2.redis为什么那么快? 来源: https://www.cnblogs.com/lchzlp/p/11031715.html

JS 单线程

。_饼干妹妹 提交于 2019-12-29 02:42:27
js单线程阻塞实例 setTimeout(function () { while (true) { } }, 1000); setTimeout(function () { alert('end 2'); }, 2000); setTimeout(function () { alert('end 1'); }, 100); alert('end'); 结果是弹出’end’、’end 1’,然后浏览器假死,就是不弹出‘end 2’。 js单线程重点: JS 是单线程的,但是却能执行异步任务, 这主要是因为 JS 中存在事件循环(Event Loop)和任务队列(Task Queue)。 事件循环: JS 会创建一个类似于 while (true) 的循环, 每执行一次循环体的过程称之为 Tick。 每次 Tick 的过程就是查看是否有待处理事件, 如果有则取出相关事件及回调函数放入执行栈中由主线程执行。 待处理的事件会存储在一个任务队列中, 也就是每次 Tick 会查看任务队列中是否有需要执行的任务。 任务队列: 异步操作会将相关回调添加到任务队列中。 而不同的异步操作添加到任务队列的时机也不同,如 onclick, setTimeout, ajax 处理的方式都不同, 这些异步操作是由浏览器内核的 webcore 来执行的。 onclick 由浏览器内核的 DOM Binding

单线程JavaScript

耗尽温柔 提交于 2019-12-29 02:38:42
最近在阅读《你不知道的JavaScript中卷》,当我看到第二部分介绍异步和回调函数的一些知识时,由于该书在第二部分1、2章对线程、事件循环的概念介绍的并非详细,因此引发了我的一系列思考。于是写下这篇小文章,记录自己对该知识点的学习和思考。 javascript单线程 由于JavaScript是单线程语言,因此,在一个进程上,只能运行一个线程,而不能多个线程同时运行。也就是说JavaScript不允许多个线程共享内存空间。因此,如果有多个线程想同时运行,则需采取排队的方式,即只有当前一个任务执行完毕,后一个任务才开始执行。 任务队列 在JavaScript中,所有任务可以分为两种,一种是同步任务,一种是异步任务。 同步任务 指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,后一个任务才会执行; 异步任务 指的是不进入主线程、而进入任务队列的任务,只有当主线程上的所有同步任务执行完毕之后,主线程才会读取任务队列,开始执行异步任务。 单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务不得不一直等待。那么这样的JavaScript的执行不是很慢吗?特别是对于长时间任务执行的时候,那么其他的任务就得不到执行。考虑这种原因,JS中将这些耗时的I/O等操作封装成了异步的方法,也就是通过 回调函数 的方式。等到同步任务执行完毕

深入理解Javascript单线程谈Event Loop

此生再无相见时 提交于 2019-12-29 02:37:22
假如面试回答 js 的运行机制时,你可能说出这么一段话: “Javascript 的事件分同步任务和异步任务,遇到同步任务就放在执行栈中执行,而碰到异步任务就放到任务队列之中,等到执行栈执行完毕之后再去执行任务队列之中的事件。 ” 但你能说出背后的原因吗? 1. 线程与进程 进程 :是系统资源分配和调度的单元。一个运行着的程序就对应了一个进程。一个进程包括了运行中的程序和程序所使用到的内存和系统资源。 线程 :线程是进程下的执行者,一个进程至少会开启一个线程(主线程),也可以开启多个线程。 2.同步和异步 同步和异步关注的是 : 消息 ( 结果 ) 通信机制。 同步 : 发出调用 后 ,在没有得到结果前,该调用不返回。但是一旦调用返回,就得到返回值 异步 : 发出调用后,调用直接返回,没有返回结果。但结果由回调函数给出,至于什么时候给出,不知道。(这个回调函数肯定是在当前 js 执行完后才执行) 3.阻塞与非阻塞 阻塞和非阻塞关注的是 : 程序在等待调用结果时的 状态 . 阻塞调用 : 调用结果返回之前,当前线程被挂起。调用线程只有在得到结果后才会返回。 非阻塞调用 : 在不能立刻得到结果之前,该调用不会阻塞当前线程。 4. 为什么 JavaScript 是单线程? JavaScript 是 单线程 ,程序按照顺序排列,前面的必须处理好,后面的才会执行。 JavaScript

单线程实现并发——协程,gevent模块

Deadly 提交于 2019-12-25 00:51:49
一 并发的本质   1 切换   2 保存状态 二 协程的概念   协程,又称微线程,纤程。英文名Coroutine。单线程下实现并发,用户从应用程序级别控制单线程下任务的切换,注意一定是遇到I/O才切。   协程的特点在于是一个线程执行,那和多线程比,协程有何优势?   最大的优势就是协程极高的执行效率。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。   第二大优势就是不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。   因为协程是一个线程执行,那怎么利用多核CPU呢?最简单的方法是多进程+协程,既充分利用多核,又充分发挥协程的高效率,可获得极高的性能。 三 gevent模块   gevent是一个基于协程的Python网络库。   需要导入猴子补丁。   方法:     g1=gevent.spawn(func,):提交任务。 生成g1,是Greenlet类     gevent.sleep():睡     gevent.joinall(可迭代对象):阻塞,知道所有选中的任务执行完毕。     g1.join()     g1.value 获取由func函数生成Greenlet类的返回值。 import