线程

代码实现

直接使用线程模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 导入线程模块
import threading

def sing():
print("我在唱歌")

if __name__ == "__main__":
#创建线程对象
t=threading.Thread(target=sing)

#可以带参,传元组,只传一个后边带逗号
#t=threading.Thread(target=sing,args=(,))

#创建执行线程
t.start()

#获取所有线程
threading.enumerate()

#查看线程数量
len(threading.enumerate())

继承线程类

1
2
3
4
5
6
7
8
9
10
11
12
13
import threading
import time

#继承threading模块的Thread类
class MyThread(threading.Thread):
def run(self):
for i in range(3):
time.sleep(1)
print(i)

if __name__ == "__main__":
t=MyThread()
t.start()

共享全局变量

  1. 当只修改全局变量的值不需在函数中使用 global声明
  2. 修改了全局变量指向的内容要在函数中使用global声明
  3. 用来传递的参数也共享

1
2
3
4
5
6
7
8
#创建锁
mutex=threading.Lock()

#上锁
mutex.acquire()

#解锁
mutex.release()

进程

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import multiprocessing

def sing1():
print("菊花台")

def sing2():
print("化蝶")

def main():
p1=multiprocessing.Process(target=sing1)
p2=multiprocessing.Process(target=sing2)
p1.start()
p2.start()

if __name__ == "__main__":
main()

队列实现进程间通信

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import multiprocessing 

#判空
#q.empty()
#判满
#q.qull()
def down_from_web(q):
#模拟数据
data=[11,22,33,44]

for temp in data:
q.put(temp)

def analysis_data(q):
watting_analysis_data=list()

#从队列中拿数据
while 1:
data=q.get()
watting_analysis_data.append(data)

if q.empty():
break
print(watting_analysis_data)

if __name__ == "__main__":
#创建队列
q=multiprocessing.Queue(4)

#创建进程通信
p1=multiprocessing.Process(target=down_from_web,args=(q,))
p2=multiprocessing.Process(target=analysis_data,args=(q,))
p1.start()
p2.start()

进程池

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import multiprocessing 

def woker(msg):
print(msg)

#进程池放3个进程
po=multiprocessing.Pool(3)

for i in range(0,10):
#使用apply_async调用进程运行
#放入进程的函数,参数(元组)
po.apply_async(woker,(i))

#关闭进程池,po不再有新的请求
po.close()

#主进程等待po中进程结束,放在close之后
po.join()

协程

一条线程时间片轮转实现多任务
在一条线程执行某函数需耗时切换另一个函数

迭代器

迭代器:存储的是生成数据的方式,占用很小的空间
例如:python2版本的range直接生成一个列表,python3版本的range存放生成数据的方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
from collections.abc import Iterable
from collections.abc import Iterator

#判断一个类是否可以迭代
#1.实现iter方法的类才可以迭代
#2.iter返回一个迭代器

#实现iter方法的类才可以迭代(可以使用for)
class Classmate(object):
def __init__(self):
self.names=list()

def add(self,name):
self.names.append(name)

#返回一个迭代器,将自己当参数传过去(为了在迭代器中调用next方法迭代自己的值)
def __iter__(self):
return ClassIterator(self)

#有iter和next方法的类为迭代器类
class ClassIterator(object):
def __init__(self,obj):
self.obj=obj
self.current_num=0

def __iter__(self):
pass

def __next__(self):
if self.current_num<len(self.obj.names):
ret=self.obj.names[self.current_num]
self.current_num+=1
return ret
#抛出异常不会在for循环可迭代对象为空时继续循环
else:
raise StopIteration

迭代器本身就可以迭代

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Classmate(object):
def __init__(self):
self.names=list()
self.current_num=0

def add(self,name):
self.names.append(name)

def __iter__(self):
return self

def __next__(self):
if self.current_num<len(self.obj.names):
ret=self.obj.names[self.current_num]
self.current_num+=1
return ret
#抛出异常不会在for循环可迭代对象为空时继续循环
else:
raise StopIteration

生成器

生成器是一种特殊的迭代器(没有iter和next方法)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def creat_num(all_num):
a,b=0,1
current_num=0
while current_num<all_num:
#函数中有yield,这个函数就是一个生成器的模版
#有yield停止,并返回yield后的值
yield a
a,b=b,a+b
current_num+=1

#调用生成器的模版,创建一个生成器对象,只创建不执行
obj=creat_num(10)

#for循环生成器时,输出第一个时执行生成器模版到yield处停止,之后的输出从yield后继续执行
for num in obj:
print(num)

注意:

  1. 可以使用next()调用生成器的next方法
  2. 生成多个生成器互不干扰
  3. 生成器对象有send方法可以传参数一般开始先用next(),如果第一个运行可以传None作为参数
1
2
3
4
5
6
7
8
9
10
next取值时要抛异常
while True:
try:
ret=next(obj)
print(ret)
#except StopIteration
#生成器模版中的return值可以通过异常获得
except Exception as ret:
print(ret.value)
break
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def creat_num(all_num):
a,b=0,1
current_num=0
while current_num<all_num:
ret=yield a
a,b=b,a+b
current_num+=1

obj=creat_num(10)

#运行到yield左边,将a的值返回
ret=next(obj)

#接着next运行,将参数赋值给yield右边,运行到下一次yield,将将a的值返回
#obj.send(None)
ret=obj.send("123")

yeild实现多任务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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()
t1=task_1()

while True:
#类似时间片轮转,遇到yeild去执行另一个
next(t1)
next(t2)

gevent实现多任务

gevent一条线程时间片轮转实现多任务
在执行等待操作时切换任务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from  gevent import monkey
import gevent
import random
import time

#有耗时操作需要
#将程序中的耗时操作代码换成gevent中自己实现的模块
monkey.patch_all()

def coroutine_work(coroutine_name):
for i in range(10):
print(coroutine_name,i)
#实际程序不一定需要使用sleep来耗时
time.sleep(random.random())

#封转好的协程操作,前一个参数为函数,后一个为传入的参数
gevent.joinall([
gevent.spawn(coroutine_work,"work1"),
gevent.spawn(coroutine_work,"work1")
])

总结

  1. 进程切换资源消耗大,效率一般
  2. 线程切换需要资源一般,效率一般
  3. 协程切换任务资源很小,效率高