并发:假的多任务
并行:真的多任务
一、线程
import threading
def test01():
while true:
print("----1----")
def test02():
while true:
print("----2---)
def main():
t1 = threading.Thread(target = test01)
t2 = threading.Thread(target = test02)
t1.start()
t2.start()
if __name__ == "__main__"
main()
1、Threading模块下的enumerate类
查看程序中所有的线程数的,返回的是一个元组
线程的运行是没有先后顺序的
2、如果创建Thread时执行的函数,运行结束,子线程也相应结束
3、当调用Thread不会创建线程,只有调用Thread创建出来对象的start方法的时候才会创建线程并且让这个线程进行工作
4、多线程共享全局变量
5、互斥锁 解决资源竞争的问题
申明互斥锁 mutex = threading.Lock()
上锁 mutex.acquire()
解锁 mutex.release()
二、进程
Import multiprocessing
def test01():
while true:
print("----1----")
def test02():
while true:
print("----2---)
def main():
t1 = multiprocessing.Process(target = test01)
t2 = multiprocessing.Process(target = test02)
t1.start()
t2.start()
if __name__ == "__main__"
main()
1.进程和线程的区别
先有进程才有线程,没有进程就不会有线程
进程是资源分配的单位,线程是操作系统调度的单位
线程实现多任务需要很少的资源
进程实现多任务需要比较多的资源
进程之间是互相独立的,线程之间共享全局变量
三、进程间的通信
queue 队列 先进先出
栈 先进后出
三、协程
1、迭代器
from collections import Iterable
from collections import Iterator
import time
class Dog(object):
def __init__(self):
self.names = list()
def add(self, name):
self.names.append(name)
def __iter__(self):
return Erha(self)
class Erha(object):
def __init__(self, obj):
self.obj = obj
self.count = 0
def __iter__(self):
pass
def __next__(self):
if self.count < len(self.obj.names):
ret = self.obj.names[self.count]
self.count += 1
return ret
else:
raise StopIteration
dog = Dog()
dog.add("大黄")
dog.add("菠菜")
dog.add("咖啡")
print("dog对象是否是一个可迭代对象:", isinstance(dog, Iterable))
dog_iter = iter(dog)
print("dog对象是否是一个迭代器:", isinstance(dog_iter, Iterator))
for name in dog:
print(name)
time.sleep(1)
2、生成器
生成器是一种特殊的迭代器。
创建生成器的第一种方式:
列表:
L = [x*2 for x in range(5)] # 返回的是生成的数据
生成器:
G = (x*2 for x in range(5)) # 返回的是生成数据的方法即对象,节省空间
for i in G:
print(i)
创建生成器的第二种方式:
如果在调用一个函数的时候发现有yield,则不是在调用函数,而是在创建一个生成器对象
每从yield取一次数据,则程序停留在yield后,数据不会丢失
例:使用生成器完成fibonacci数列:
def main(all_count):
a, b = 0, 1
count = 0
while count < all_count:
yield a
a, b = b, a + b
count += 1
if __name__ == "__main__":
obj = main(10)
for i in obj:
print(i)
例:使用yield完成多任务
import time
def task1():
while True:
print("-----1-----")
time.sleep(0.1)
yield
def task2():
while True:
print("-----2-----")
time.sleep(0.1)
yield
def main():
t1 = task1()
t2 = task2()
while True:
next(t1)
next(t2)
if __name__ == "__main__":
main()
例:使用greenlet实现多任务
from greenlet import greenlet
import time
def task1():
while True:
print("-----1-----")
t2.switch()
time.sleep(0.5)
def task2():
while True:
print("-----2-----")
t1.switch()
time.sleep(0.5)
t1 = greenlet(task1)
t2 = greenlet(task2)
t1.switch()
例:使用gevent完成多任务
import gevent
from gevent import monkey
import time
# 将程序中的耗时操作换成自己实现的方式,而非gevent中的耗时方法
monkey.patch_all()
def task1():
while True:
print(gevent.getcurrent(), "-----1-----") # gevent.getcurrent()获取当前打印的对象
# gevent.sleep(0.1)
time.sleep(0.1)
def task2():
while True:
print(gevent.getcurrent(), "-----2-----")
# gevent.sleep(0.1)
time.sleep(0.1)
# g1 = gevent.spawn(task1)
# g2 = gevent.spawn(task2)
# g1.join()
# g2.join()
gevent.joinall([
gevent.spawn(task1),
gevent.spawn(task2)
])
总结:greenlet、gevent底层都是通过yield实现,只不过是对yield的一次封装,推荐使用gevent
总结:
1、进程是资源分配的单位
2、线程是操作系统调度的单位
3、进程切换需要的资源很大,效率很低
4、线程切换需要的资源一般,效率一般(在不考虑GIL的情况下)
5、协程切换任务资源很小,效率高
6、多进程、多线程根据CPU核数不一样可能是并行的,但是协程是在一个线程中,所以是并发