python后端学习(五)迭代器、生成器、协程
迭代器
迭代是访问集合元素的一种方式。迭代器是一个可以记住遍历的位置的对象。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
1. 可迭代对象
我们已经知道可以对list、tuple、str等类型的数据使用for…in…的循环语法从其中依次拿到数据进行使用,我们把这样的过程称为遍历,也叫迭代。
但是,是否所有的数据类型都可以放到for…in…的语句中,然后让for…in…每次从中取出一条数据供我们使用,即供我们迭代吗?
>>> for i in 100:
... print(i)
...
Traceback (most recent call last):File "<stdin>", line 1, in <module>
TypeError: 'int' object is not iterable
>>>
# int整型不是iterable,即int整型不是可以迭代的# 我们自定义一个容器MyList用来存放数据,可以通过add方法向其中添加数据
>>> class MyList(object):
... def __init__(self):
... self.container = []
... def add(self, item):
... self.container.append(item)
...
>>> mylist = MyList()
>>> mylist.add(1)
>>> mylist.add(2)
>>> mylist.add(3)
>>> for num in mylist:
... print(num)
...
Traceback (most recent call last):File "<stdin>", line 1, in <module>
TypeError: 'MyList' object is not iterable
>>>
# MyList容器的对象也是不能迭代的
我们自定义了一个容器类型MyList,在将一个存放了多个数据的MyList对象放到for…in…的语句中,发现for…in…并不能从中依次取出一条数据返回给我们,也就说我们随便封装了一个可以存放多条数据的类型却并不能被迭代使用。
我们把可以通过for…in…这类语句迭代读取一条数据供我们使用的对象称之为可迭代对象(Iterable)。
2. 如何判断一个对象是否可以迭代
可以使用 isinstance() 判断一个对象是否是 Iterable 对象:
In [50]: from collections import IterableIn [51]: isinstance([], Iterable)
Out[51]: TrueIn [52]: isinstance({}, Iterable)
Out[52]: TrueIn [53]: isinstance('abc', Iterable)
Out[53]: TrueIn [54]: isinstance(mylist, Iterable)
Out[54]: FalseIn [55]: isinstance(100, Iterable)
Out[55]: False
3. 可迭代对象的本质
我们分析对可迭代对象进行迭代使用的过程,发现每迭代一次(即在for…in…中每循环一次)都会返回对象中的下一条数据,一直向后读取数据直到迭代了所有数据后结束。那么,在这个过程中就应该有一个“人”去记录每次访问到了第几条数据,以便每次迭代都可以返回下一条数据。我们把这个能帮助我们进行数据迭代的“人”称为迭代器(Iterator)。
可迭代对象的本质就是可以向我们提供一个这样的中间“人”即迭代器帮助我们对其进行迭代遍历使用。
可迭代对象通过__iter__方法向我们提供一个迭代器,我们在迭代一个可迭代对象的时候,实际上就是先获取该对象提供的一个迭代器,然后通过这个迭代器来依次获取对象中的每一个数据.
那么也就是说,一个具备了__iter__方法的对象,就是一个可迭代对象。
>>> class MyList(object):
... def __init__(self):
... self.container = []
... def add(self, item):
... self.container.append(item)
... def __iter__(self):
... """返回一个迭代器"""
... # 我们暂时忽略如何构造一个迭代器对象
... pass
...
>>> mylist = MyList()
>>> from collections import Iterable
>>> isinstance(mylist, Iterable)
True
>>>
# 这回测试发现添加了__iter__方法的mylist对象已经是一个可迭代对象了
4. iter()函数与next()函数
list、tuple等都是可迭代对象,我们可以通过iter()函数获取这些可迭代对象的迭代器。然后我们可以对获取到的迭代器不断使用next()函数来获取下一条数据。iter()函数实际上就是调用了可迭代对象的__iter__方法。
>>> li = [11, 22, 33, 44, 55]
>>> li_iter = iter(li)
>>> next(li_iter)
11
>>> next(li_iter)
22
>>> next(li_iter)
33
>>> next(li_iter)
44
>>> next(li_iter)
55
>>> next(li_iter)
Traceback (most recent call last):File "<stdin>", line 1, in <module>
StopIteration
>>>
注意,当我们已经迭代完最后一个数据之后,再次调用next()函数会抛出StopIteration的异常,来告诉我们所有数据都已迭代完成,不用再执行next()函数了。
5. 如何判断一个对象是否是迭代器
可以使用 isinstance() 判断一个对象是否是 Iterator 对象:
In [56]: from collections import IteratorIn [57]: isinstance([], Iterator)
Out[57]: FalseIn [58]: isinstance(iter([]), Iterator)
Out[58]: TrueIn [59]: isinstance(iter("abc"), Iterator)
Out[59]: True
6. 迭代器Iterator
通过上面的分析,我们已经知道,迭代器是用来帮助我们记录每次迭代访问到的位置,当我们对迭代器使用next()函数的时候,迭代器会向我们返回它所记录位置的下一个位置的数据。实际上,在使用next()函数的时候,调用的就是迭代器对象的__next__方法(Python3中是对象的__next__方法,Python2中是对象的next()方法)。所以,我们要想构造一个迭代器,就要实现它的__next__方法。但这还不够,python要求迭代器本身也是可迭代的,所以我们还要为迭代器实现__iter__方法,而__iter__方法要返回一个迭代器,迭代器自身正是一个迭代器,所以迭代器的__iter__方法返回自身即可。
一个实现了__iter__方法和__next__方法的对象,就是迭代器。
class MyList(object):"""自定义的一个可迭代对象"""def __init__(self):self.items = []def add(self, val):self.items.append(val)def __iter__(self):myiterator = MyIterator(self)return myiteratorclass MyIterator(object):"""自定义的供上面可迭代对象使用的一个迭代器"""def __init__(self, mylist):self.mylist = mylist# current用来记录当前访问到的位置self.current = 0def __next__(self):if self.current < len(self.mylist.items):item = self.mylist.items[self.current]self.current += 1return itemelse:raise StopIterationdef __iter__(self):return selfif __name__ == '__main__':mylist = MyList()mylist.add(1)mylist.add(2)mylist.add(3)mylist.add(4)mylist.add(5)for num in mylist:print(num)
迭代器的实现
import time
from collections import Iterable
from collections import Iteratorclass Classmate(object):def __init__(self):self.names = list()def add(self, name):self.names.append(name)def __iter__(self):"""如果想要一个对象称为一个 可以迭代的对象,即可以使用for,那么必须实现__iter__方法"""return ClassIterator(self)class ClassIterator(object):def __init__(self, obj):self.obj = objself.current_num = 0def __iter__(self):passdef __next__(self):if self.current_num < len(self.obj.names):ret = self.obj.names[self.current_num]self.current_num += 1return retelse:raise StopIterationclassmate = Classmate()
classmate.add("老王")
classmate.add("王二")
classmate.add("张三")# print("判断classmate是否是可以迭代的对象:", isinstance(classmate, Iterable))
# classmate_iterator = iter(classmate)
# print("判断classmate_iterator是否是迭代器:", isinstance(classmate_iterator, Iterator))
# print(next(classmate_iterator))for name in classmate:print(name)time.sleep(1)
import time
from collections import Iterable
from collections import Iteratorclass Classmate(object):def __init__(self):self.names = list()self.current_num = 0def add(self, name):self.names.append(name)def __iter__(self):"""如果想要一个对象称为一个 可以迭代的对象,即可以使用for,那么必须实现__iter__方法"""return self # 调用iter(xxobj)的时候 只要__iter__方法返回一个 迭代器即可,至于是自己 还是 别的对象都可以的, 但是要保证是一个迭代器(即实现了 __iter__ __next__方法)def __next__(self):if self.current_num < len(self.names):ret = self.names[self.current_num]self.current_num += 1return retelse:raise StopIterationclassmate = Classmate()
classmate.add("老王")
classmate.add("王二")
classmate.add("张三")# print("判断classmate是否是可以迭代的对象:", isinstance(classmate, Iterable))
# classmate_iterator = iter(classmate)
# print("判断classmate_iterator是否是迭代器:", isinstance(classmate_iterator, Iterator))
# print(next(classmate_iterator))for name in classmate:print(name)time.sleep(1)
7. for…in…循环的本质
for item in Iterable 循环的本质就是先通过iter()函数获取可迭代对象Iterable的迭代器,然后对获取到的迭代器不断调用next()方法来获取下一个值并将其赋值给item,当遇到StopIteration的异常后循环结束。
8. 迭代器的应用场景
我们发现迭代器最核心的功能就是可以通过next()函数的调用来返回下一个数据值。如果每次返回的数据值不是在一个已有的数据集合中读取的,而是通过程序按照一定的规律计算生成的,那么也就意味着可以不用再依赖一个已有的数据集合,也就是说不用再将所有要迭代的数据都一次性缓存下来供后续依次读取,这样可以节省大量的存储(内存)空间。
举个例子,比如,数学中有个著名的斐波拉契数列(Fibonacci),数列中第一个数为0,第二个数为1,其后的每一个数都可由前两个数相加得到:
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, …
现在我们想要通过for…in…循环来遍历迭代斐波那契数列中的前n个数。那么这个斐波那契数列我们就可以用迭代器来实现,每次迭代都通过数学计算来生成下一个数。
fibonacci-1.py
nums = list()a = 0
b = 1
i = 0
while i < 10:nums.append(a)a, b = b, a+bi += 1for num in nums:print(num)
fibonacci-2 迭代器.py
class Fibonacci(object):def __init__(self, all_num):self.all_num = all_numself.current_num = 0self.a = 0self.b = 1def __iter__(self):return selfdef __next__(self):if self.current_num < self.all_num:ret = self.aself.a, self.b = self.b, self.a+self.bself.current_num += 1return retelse:raise StopIterationfibo = Fibonacci(10)for num in fibo:print(num)
使用用生成器完成fibonacci.py
def create_num(all_num):print("----1---")# a = 0# b = 1a, b = 0, 1current_num = 0while current_num < all_num:print("----2---")# print(a)yield a # 如果一个函数中有yield语句,那么这个就不在是函数,而是一个生成器的模板print("----3---")a, b = b, a+bcurrent_num += 1print("----4---")# 如果在调用create_num的时候,发现这个函数中有yield那么此时,不是调用函数,而是创建一个生成器对象
obj = create_num(10)ret = next(obj)
print(ret)ret = next(obj)
print(ret)obj2 = create_num(2)ret = next(obj2)
print(ret)# for num in obj:
# print(num)
python2中 range(10)与xrange(10)的区别:
range(10)生成列表包含1-10
xrange(10)返回生成数据的方式
9. 并不是只有for循环能接收可迭代对象
除了for循环能接收可迭代对象,list、tuple等也能接收。
li = list(FibIterator(15))
print(li)
tp = tuple(FibIterator(6))
print(tp)
生成器
利用迭代器,我们可以在每次迭代获取数据(通过next()方法)时按照特定的规律进行生成。但是我们在实现一个迭代器时,关于当前迭代到的状态需要我们自己记录,进而才能根据当前状态生成下一个数据。为了达到记录当前状态,并配合next()函数进行迭代使用,我们可以采用更简便的语法,即生成器(generator)。生成器是一类特殊的迭代器。
1.创建生成器方法1
要创建一个生成器,有很多种方法。第一种方法很简单,只要把一个列表生成式的 [ ] 改成 ( )
In [15]: L = [ x*2 for x in range(5)]In [16]: L
Out[16]: [0, 2, 4, 6, 8]In [17]: G = ( x*2 for x in range(5))In [18]: G
Out[18]: <generator object <genexpr> at 0x7f626c132db0>In [19]:
创建 L 和 G 的区别仅在于最外层的 [ ] 和 ( ) , L 是一个列表,而 G 是一个生成器。我们可以直接打印出列表L的每一个元素,而对于生成器G,我们可以按照迭代器的使用方法来使用,即可以通过next()函数、for循环、list()等方法使用。
In [19]: next(G)
Out[19]: 0In [20]: next(G)
Out[20]: 2In [21]: next(G)
Out[21]: 4In [22]: next(G)
Out[22]: 6In [23]: next(G)
Out[23]: 8In [24]: next(G)
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
<ipython-input-24-380e167d6934> in <module>()
----> 1 next(G)StopIteration:In [25]:
In [26]: G = ( x*2 for x in range(5))In [27]: for x in G:....: print(x)....:
0
2
4
6
8In [28]:
2. 创建生成器方法2
generator非常强大。如果推算的算法比较复杂,用类似列表生成式的 for 循环无法实现的时候,还可以用函数来实现。
简单来说:只要在def中有yield关键字的 就称为 生成器
def create_num(all_num):print("----1---")# a = 0# b = 1a, b = 0, 1current_num = 0while current_num < all_num:print("----2---")# print(a)yield a # 如果一个函数中有yield语句,那么这个就不在是函数,而是一个生成器的模板print("----3---")a, b = b, a+bcurrent_num += 1print("----4---")# 如果在调用create_num的时候,发现这个函数中有yield那么此时,不是调用函数,而是创建一个生成器对象
obj = create_num(10)
# 多个生成器互不干扰
obj2 = create_num(2)ret = next(obj)
print("obj:", ret)ret = next(obj)
print("obj:", ret)ret = next(obj2)
print("obj2:", ret)ret = next(obj)
print("obj:", ret)ret = next(obj)
print("obj:", ret)
ret = next(obj)
print("obj:", ret)
# for num in obj:
# print(num)ret = next(obj2)
print("obj2:", ret)ret = next(obj2)
print("obj2:", ret)
def create_num(all_num):# a = 0# b = 1a, b = 0, 1current_num = 0while current_num < all_num:# print(a)yield a # 如果一个函数中有yield语句,那么这个就不在是函数,而是一个生成器的模板a, b = b, a+bcurrent_num += 1return "ok...."obj2 = create_num(50)while True:try:ret = next(obj2)print(ret)except Exception as ret:# 想要得到return的值需要 在except跑出结果的值print(ret.value)break
总结
- 使用了yield关键字的函数不再是函数,而是生成器。(使用了yield的函数就是生成器)
- yield关键字有两点作用:
1.保存当前运行状态(断点),然后暂停执行,即将生成器(函数)挂起
2.将yield关键字后面表达式的值作为返回值返回,此时可以理解为起到了return的作用 - 可以使用next()函数让生成器从断点处继续执行,即唤醒生成器(函数)
- Python3中的生成器可以使用return返回最终运行的返回值,而Python2中的生成器不允许使用return返回一个返回值(即可以使用return从生成器中退出,但return后不能有任何表达式)。
3. 使用send唤醒
我们除了可以使用next()函数来唤醒生成器继续执行外,还可以使用send()函数来唤醒执行。使用send()函数的一个好处是可以在唤醒的同时向断点处传入一个附加数据。
例子:执行到yield时,create_num函数作用暂时保存,返回a的值; ret 接收下次c.send(“python”),send发送过来的值,next(obj)等价obj.send(None)
def create_num(all_num):a, b = 0, 1current_num = 0while current_num < all_num:ret = yield aprint(">>>ret>>>>", ret)a, b = b, a+bcurrent_num += 1obj = create_num(10)# obj.send(None) # send一般不会放到第一次启动生成器,如果非要这样做 那么传递Noneret = next(obj)
print(ret)# send里面的数据会 传递给第5行,当做yield a的结果,然后ret保存这个结果,,,
# send的结果是下一次调用yield时 yield后面的值
ret = obj.send("hahahha")
print(ret)
协程
协程,又称微线程,纤程。英文名Coroutine。
协程是啥
协程是python个中另外一种实现多任务的方式,只不过比线程更小占用更小执行单元(理解为需要的资源)。 为啥说它是一个执行单元,因为它自带CPU上下文。这样只要在合适的时机, 我们可以把一个协程 切换到另一个协程。 只要这个过程中保存或恢复 CPU上下文那么程序还是可以运行的。
通俗的理解:在一个线程中的某个函数,可以在任何地方保存当前函数的一些临时变量等信息,然后切换到另外一个函数中执行,注意不是通过调用函数的方式做到的,并且切换的次数以及什么时候再切换到原来的函数都由开发者自己确定
协程和线程差异
在实现多任务时, 线程切换从系统层面远不止保存和恢复 CPU上下文这么简单。 操作系统为了程序运行的高效性每个线程都有自己缓存Cache等等数据,操作系统还会帮你做这些数据的恢复操作。 所以线程的切换非常耗性能。但是协程的切换只是单纯的操作CPU的上下文,所以一秒钟切换个上百万次系统都抗的住。
使用yield实现多任务(写成).py
import timedef task_1():while True:print("---1----")time.sleep(0.1)yielddef task_2():while True:print("---2----")time.sleep(0.1)yielddef main():t1 = task_1()t2 = task_2()# 先让t1运行一会,当t1中遇到yield的时候,再返回到24行,然后# 执行t2,当它遇到yield的时候,再次切换到t1中# 这样t1/t2/t1/t2的交替运行,最终实现了多任务....协程while True:next(t1)next(t2)if __name__ == "__main__":main()
协程-greenlet
greenlet
为了更好使用协程来完成多任务,python中的greenlet模块对其封装,从而使得切换任务变的更加简单
安装方式
使用如下命令安装greenlet模块:
sudo pip3 install greenlet
#coding=utf-8
from greenlet import greenlet
import timedef test1():while True:print ("---A--")gr2.switch()time.sleep(0.5)def test2():while True:print ("---B--")gr1.switch()time.sleep(0.5)gr1 = greenlet(test1)
gr2 = greenlet(test2)#切换到gr1中运行
gr1.switch()
协程-gevent
greenlet已经实现了协程,但是这个还的人工切换,是不是觉得太麻烦了,不要捉急,python还有一个比greenlet更强大的并且能够自动切换任务的模块gevent
其原理是当一个greenlet遇到IO(指的是input output 输入输出,比如网络、文件操作等)操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。
由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO
安装
pip3 install gevent
gevent实现多任务.py
import gevent
import timedef f1(n):for i in range(n):print(gevent.getcurrent(), i)# 遇到这个延时不会切换到其他函数运行# time.sleep(0.5) # 用来模拟一个耗时操作,注意不是time模块中的sleep 遇到延迟自动切换运行其他函数gevent.sleep(0.5)def f2(n):for i in range(n):print(gevent.getcurrent(), i)# time.sleep(0.5)gevent.sleep(0.5)def f3(n):for i in range(n):print(gevent.getcurrent(), i)# time.sleep(0.5)gevent.sleep(0.5)print("----1---")
g1 = gevent.spawn(f1, 5)
print("----2---")
g2 = gevent.spawn(f2, 5)
print("----3---")
g3 = gevent.spawn(f3, 5)
print("----4---")
g1.join()
g2.join()
g3.join()
协程的意义:程序遇到堵塞、延时的操作,切换到其他函数继续执行。
要想使用gevent,要把代码中所有遇到的堵塞、延迟操作,替换为gevent中的操作,对于已经构建的代码没有用到gevent,就需要代码重构?避免代码重构就要给gevent打补丁的方法。
gevent使用demo.py
import gevent
import time
from gevent import monkey# 有耗时操作时需要
monkey.patch_all() # 将程序中用到的耗时操作的代码,换为gevent中自己实现的模块def f1(n):for i in range(n):print(gevent.getcurrent(), i)time.sleep(0.5)def f2(n):for i in range(n):print(gevent.getcurrent(), i)time.sleep(0.5)def f3(n):for i in range(n):print(gevent.getcurrent(), i)time.sleep(0.5)# 省去手动添加 join的操作
gevent.joinall([gevent.spawn(f1, 5),gevent.spawn(f2, 5),gevent.spawn(f3, 5)
])
协程一般使用gevent去实现,不推荐使用yield 和 greenlet的方式
案例:使用gevent下载图片
import urllib.request
import gevent
from gevent import monkeymonkey.patch_all()def downloader(img_name, img_url):req = urllib.request.urlopen(img_url)img_content = req.read()with open(img_name, "wb") as f:f.write(img_content)def main():gevent.joinall([gevent.spawn(downloader, "3.jpg", "https://rpic.douyucdn.cn/appCovers/2017/09/22/1760931_20170922133718_big.jpg"),gevent.spawn(downloader, "4.jpg", "https://rpic.douyucdn.cn/appCovers/2017/09/17/2308890_20170917232900_big.jpg")])if __name__ == '__main__':main()
进程、线程、协程对比
请仔细理解如下的通俗描述
- 有一个老板想要开个工厂进行生产某件商品(例如剪子)
- 他需要花一些财力物力制作一条生产线,这个生产线上有很多的器件以及材料这些所有的 为了能够生产剪子而准备的资源称之为:进程
- 只有生产线是不能够进行生产的,所以老板的找个工人来进行生产,这个工人能够利用这些材料最终一步步的将剪子做出来,这个来做事情的工人称之为:线程
- 这个老板为了提高生产率,想到3种办法:
- 在这条生产线上多招些工人,一起来做剪子,这样效率是成倍増长,即单进程 多线程方式
- 老板发现这条生产线上的工人不是越多越好,因为一条生产线的资源以及材料毕竟有限,所以老板又花了些财力物力购置了另外一条生产线,然后再招些工人这样效率又再一步提高了,即多进程 多线程方式
- 老板发现,现在已经有了很多条生产线,并且每条生产线上已经有很多工人了(即程序是多进程的,每个进程中又有多个线程),为了再次提高效率,老板想了个损招,规定:如果某个员工在上班时临时没事或者再等待某些条件(比如等待另一个工人生产完谋道工序 之后他才能再次工作) ,那么这个员工就利用这个时间去做其它的事情,那么也就是说:如果一个线程等待某些条件,可以充分利用这个时间去做其它事情,其实这就是:协程方式
简单总结
- 进程是资源分配的单位
- 线程是操作系统调度的单位
- 进程切换需要的资源很最大,效率很低
- 线程切换需要的资源一般,效率一般(当然了在不考虑GIL的情况下)
- 协程切换任务资源很小,效率高
- 多进程、多线程根据cpu核数不一样可能是并行的,但是协程是在一个线程中 所以是并发
python后端学习(五)迭代器、生成器、协程相关推荐
- python的装饰器、迭代器、yield_python装饰器,迭代器,生成器,协程
python装饰器[1] 首先先明白以下两点 #嵌套函数 defout1():definner1():print(1234) inner1()#当没有加入inner时out()不会打印输出1234,当 ...
- python模拟春节集五福_过年扫五福,干脆我用Python做一个五福生成器
原标题:过年扫五福,干脆我用Python做一个五福生成器 新的一年又要到来了,各个大的公司又在这年末为大家送上了新春的祝福,支付宝还是延续了这几年的传统,在年末为大家送上了集五福的活动,为了大家能更快 ...
- python线程进程协程面试_Python学习经验之谈:关于协程的理解和其相关面试问题...
都知道Python非常适合初学者学习来入门编程,昨天有伙伴留言说面试了Python岗位,问及了一个关于协程的问题,想了想还是跟大家出一篇协程相关的文章和在Python面试中可能会问及的相关面试问题.都 ...
- Python 中的黑暗角落(二):生成器协程的调度问题
前作介绍了 Python 中的 yield 关键字.此篇介绍如何使用 yield 表达式,在 Python 中实现一个最基本的协程调度示例,避免 I/O 操作占用大量 CPU 计算时间. 协程及其特点 ...
- Python之路--Python基础12--并发编程之协程
一.协程介绍 1.引子 本节的主题是基于单线程来实现并发,即只用一个主线程(很明显可利用的cpu只有一个)情况下实现并发,为此我们需要先回顾下并发的本质:切换+保存状态.cpu正在运行一个任务,会在两 ...
- python异步爬虫_Python实现基于协程的异步爬虫
Python实现基于协程的异步爬虫 一.课程介绍 1. 课程来源 本课程核心部分来自<500 lines or less>项目,作者是来自 MongoDB 的工程师 A. Jesse Ji ...
- python提高——进程、线程、协程对比及代码实现
目录 1多任务 1.1并发 1.2并行 2线程 2.1引入线程 2.2线程进行顺序 2.3线程封装 2.4多线程-共享全局变量 2.5资源竞争 2.6互斥锁 2.7死锁 3进程 3.1进程创建 3.2 ...
- Python后端学习路线
目录 一.Python语言基础 二.计算机基础 三.Python语言高级 四.前端技术 五.前端框架及前端进阶技术 六.后端框架 七.安全技术 八.版本控制工具 九.Linux基础 十.测试技术 十一 ...
- 〖Python〗-- 线程、进程、协程
[线程.进程.协程] 学习进程.线程.协程,引申一些内容 为什么要学习进程和线程: 进程和线程目的是为了:提高执行效率 现代操作系统比如Mac OS X,UNIX,Linux,Windows等,都是支 ...
最新文章
- 让我再撸一次HashMap
- 结合Android去水印APP谈谈分区存储
- 将之前写完的猜数字游戏改为通过javabean_有了这些互动小游戏,知识竞赛更精彩了...
- 七、Mosquito 集群搭建
- python绘制直角坐标系_小白学 Python 数据分析(16):Matplotlib(一)坐标系
- python蟒蛇绘制实例分析_011 实例2-Python蟒蛇绘制
- stotybord如何添加子视图_Revit软件技巧合集(建筑构件、视图处理、建筑表现、高级技巧)...
- 怎么在云服务器上布项目,怎么在云服务器上布项目
- mysql 游标的简单_mysql 简单游标
- 「1s」即可!用 VS Code 一键玩转 GitHub 代码!
- vs2003 打开VS.NET项目时遇到 “无法从web服务器获取项目文件” 解决方案
- ArcGIS图层介绍
- ifs 报表开发手册_店长工作手册:连锁总部店长复制手册之店长手册对门店经营管理的编写...
- WLAN概述——无线网络简介
- JSON与JAVA数据的转换。JSONObject.fromObject()和JSONObject.toBean()
- 三相逆变器仿真matlab,在MATLAB中实现三相电压逆变器仿真
- mysql 临时表权限_MySQL临时表浅析
- Windows 10 下生成 ssh 密钥
- 一个完整的计算机系统有哪五大组成部分,一个完整的计算机系统由哪些部份组成...
- windows10下模拟器运行LVGL记录
热门文章
- 数字化时代-20:一张图看清中国金融市场的轮廓
- 我的世界服务器指令系统,我的世界中国版最全指令 MC指令最全合集
- 求几道C++题,不用排版,代码尽量简单,方便理解
- php抓ik123音乐,IK123下载工具收藏下载网络DJ音乐教程
- filebeat重复采集数据问题排查
- ffmpeg 将.m4a音频转换为.wav文件
- 计算机故障代码0098,P0098故障码_P0098故障码是什么故障、排除方法、怎么消除_车主指南...
- 如何建立Multi-Step(多步预测)的LSTM时间序列模型(以对家庭用电预测为例)
- luooj P1655手套
- Big Faceless Java PDF Library[BFO]