25_2.多线程之_thread模块
编写一段子程序,依次执行两次:
"""
单线程示例
"""
import time
def worker(n):
print('子程序开始于:{}'.format(time.ctime()))
time.sleep(n)
print('子程序结束于:{}'.format(time.ctime()))
def main():
print('[主程序开始于:{}'.format(time.ctime()))
worker(4)
worker(2)
print('[主程序结束于:{}'.format(time.ctime()))
if __name__ == '__main__':
main()
输出:
[主程序开始于:Sun Feb 23 16:25:22 2020
子程序开始于:Sun Feb 23 16:25:22 2020
子程序结束于:Sun Feb 23 16:25:26 2020
子程序开始于:Sun Feb 23 16:25:26 2020
子程序结束于:Sun Feb 23 16:25:28 2020
[主程序结束于:Sun Feb 23 16:25:28 2020
如果想让两次子程序并行运行,引入_thread模块:
"""
多线程示例
"""
import time
import _thread
def worker(n):
print('子程序开始于:{}'.format(time.ctime()))
time.sleep(n)
print('子程序结束于:{}'.format(time.ctime()))
def main():
print('[主程序开始于:{}'.format(time.ctime()))
# 开始并行线程
# 第一个参数是要运行的函数名,不加括号
# 第二个参数是要运行的函数的参数,以元组的形式,如果只有一个参数,要加逗号
_thread.start_new_thread(worker, (4,))
_thread.start_new_thread(worker, (2,))
print('[主程序结束于:{}'.format(time.ctime()))
if __name__ == '__main__':
main()
输出:
[主程序开始于:Sun Feb 23 16:33:52 2020
[主程序结束于:Sun Feb 23 16:33:52 2020
子程序开始于:Sun Feb 23 16:33:52 2020
跟预想的不一样,因为_thread模块没有控制进程结束机制:
"""
多线程示例
"""
import time
import _thread
def worker(n):
print('子程序开始于:{}'.format(time.ctime()))
time.sleep(n)
print('子程序结束于:{}'.format(time.ctime()))
def main():
print('[主程序开始于:{}'.format(time.ctime()))
# 开始并行线程
# 第一个参数是要运行的函数名,不加括号
# 第二个参数是要运行的函数的参数,以元组的形式,如果只有一个参数,要加逗号
_thread.start_new_thread(worker, (4,))
_thread.start_new_thread(worker, (2,))
time.sleep(6)
print('[主程序结束于:{}'.format(time.ctime()))
if __name__ == '__main__':
main()
输出:
[主程序开始于:Sun Feb 23 16:37:21 2020
子程序开始于:Sun Feb 23 16:37:21 2020
子程序开始于:Sun Feb 23 16:37:21 2020
子程序结束于:Sun Feb 23 16:37:23 2020
子程序结束于:Sun Feb 23 16:37:25 2020
[主程序结束于:Sun Feb 23 16:37:27 2020
主程序执行的时间由time.sleep()里面的参数控制。
25_3.多线程之threading模块
使用threading模块改造上面的实例:
"""
threading模块示例
"""
import time
import threading
def worker(n):
print('子程序开始于:{}'.format(time.ctime()))
time.sleep(n)
print('子程序结束于:{}'.format(time.ctime()))
def main():
print('[主程序开始于:{}'.format(time.ctime()))
# 开始并行线程
# 第一个参数是要运行的函数名,不加括号
# 第二个参数是要运行的函数的参数,以元组的形式,如果只有一个参数,要加逗号
# _thread.start_new_thread(worker, (4,))
# _thread.start_new_thread(worker, (2,))
# time.sleep(6)
threads = []
t1 = threading.Thread(target=worker, args=(4,))
threads.append(t1)
t2 = threading.Thread(target=worker, args=(2,))
threads.append(t2)
for t in threads:
t.start()
print('[主程序结束于:{}'.format(time.ctime()))
if __name__ == '__main__':
main()
输出:
[主程序开始于:Mon Feb 24 10:10:38 2020
子程序开始于:Mon Feb 24 10:10:38 2020
子程序开始于:Mon Feb 24 10:10:38 2020[主程序结束于:Mon Feb 24 10:10:38 2020
子程序结束于:Mon Feb 24 10:10:40 2020
子程序结束于:Mon Feb 24 10:10:42 2020
和预想的不一样。子程序还没结束主程序就已经结束了。可加入t.join():
"""
threading模块示例
"""
import time
import threading
def worker(n):
print('子程序开始于:{}'.format(time.ctime()))
time.sleep(n)
print('子程序结束于:{}'.format(time.ctime()))
def main():
print('[主程序开始于:{}'.format(time.ctime()))
# 开始并行线程
# 第一个参数是要运行的函数名,不加括号
# 第二个参数是要运行的函数的参数,以元组的形式,如果只有一个参数,要加逗号
# _thread.start_new_thread(worker, (4,))
# _thread.start_new_thread(worker, (2,))
# time.sleep(6)
threads = []
t1 = threading.Thread(target=worker, args=(4,))
threads.append(t1)
t2 = threading.Thread(target=worker, args=(2,))
threads.append(t2)
for t in threads:
t.start()
# 要求主程序等待
for t in threads:
t.join()
print('[主程序结束于:{}'.format(time.ctime()))
if __name__ == '__main__':
main()
输出:
[主程序开始于:Mon Feb 24 10:16:30 2020
子程序开始于:Mon Feb 24 10:16:30 2020
子程序开始于:Mon Feb 24 10:16:30 2020
子程序结束于:Mon Feb 24 10:16:32 2020
子程序结束于:Mon Feb 24 10:16:34 2020
[主程序结束于:Mon Feb 24 10:16:34 2020
如果想区分不同的子程序,谁先执行,谁后执行,可使用threading.current_thread().name显示当前线程名字:
"""
threading模块示例
"""
import time
import threading
def worker(n):
print('{}子程序开始于:{}'.format(threading.current_thread().name, time.ctime()))
time.sleep(n)
print('{}子程序结束于:{}'.format(threading.current_thread().name, time.ctime()))
def main():
print('[主程序开始于:{}'.format(time.ctime()))
# 开始并行线程
# 第一个参数是要运行的函数名,不加括号
# 第二个参数是要运行的函数的参数,以元组的形式,如果只有一个参数,要加逗号
# _thread.start_new_thread(worker, (4,))
# _thread.start_new_thread(worker, (2,))
# time.sleep(6)
threads = []
t1 = threading.Thread(target=worker, args=(4,))
threads.append(t1)
t2 = threading.Thread(target=worker, args=(2,))
threads.append(t2)
for t in threads:
t.start()
# 要求主程序等待
for t in threads:
t.join()
print('[主程序结束于:{}'.format(time.ctime()))
if __name__ == '__main__':
main()
输出:
[主程序开始于:Mon Feb 24 10:21:38 2020
Thread-1子程序开始于:Mon Feb 24 10:21:38 2020
Thread-2子程序开始于:Mon Feb 24 10:21:38 2020
Thread-2子程序结束于:Mon Feb 24 10:21:40 2020
Thread-1子程序结束于:Mon Feb 24 10:21:42 2020
[主程序结束于:Mon Feb 24 10:21:42 2020
也可以构造Thread派生类,重写run方法逻辑构造子线程:
"""
threading+构造Thread派生类示例
"""
import time
import threading
def worker(n):
print('{}子程序开始于:{}'.format(threading.current_thread().name, time.ctime()))
time.sleep(n)
print('{}子程序结束于:{}'.format(threading.current_thread().name, time.ctime()))
class MyThread(threading.Thread):
def __init__(self, func, args):
threading.Thread.__init__(self)
self.func = func
self.args = args
def run(self):
# 因为输入的参数是元组形式,需要解包,所以在前面加一个*
self.func(*self.args)
def main():
print('[主程序开始于:{}'.format(time.ctime()))
# 开始并行线程
# 第一个参数是要运行的函数名,不加括号
# 第二个参数是要运行的函数的参数,以元组的形式,如果只有一个参数,要加逗号
# _thread.start_new_thread(worker, (4,))
# _thread.start_new_thread(worker, (2,))
# time.sleep(6)
threads = []
# t1 = threading.Thread(target=worker, args=(4,))
t1 = MyThread(worker, (4,))
threads.append(t1)
# t2 = threading.Thread(target=worker, args=(2,))
t2 = MyThread(worker, (2,))
threads.append(t2)
for t in threads:
t.start()
# 要求主程序等待
for t in threads:
t.join()
print('[主程序结束于:{}'.format(time.ctime()))
if __name__ == '__main__':
main()
输出:
[主程序开始于:Mon Feb 24 10:31:23 2020
Thread-1子程序开始于:Mon Feb 24 10:31:23 2020
Thread-2子程序开始于:Mon Feb 24 10:31:23 2020
Thread-2子程序结束于:Mon Feb 24 10:31:25 2020
Thread-1子程序结束于:Mon Feb 24 10:31:27 2020
[主程序结束于:Mon Feb 24 10:31:27 2020
25_4.同步锁
编写一个子程序,往一个空列表里依次从小到大放入1到5这5个数,创建3个子线程,执行3次:
"""
同步原语:锁
"""
import threading
import time
eggs = []
def put_egg(n, lst):
for i in range(1, n+1):
lst.append(i)
def main():
threads = []
for i in range(3):
t = threading.Thread(target=put_egg, args=(5, eggs))
threads.append(t)
for t in threads:
t.start()
for t in threads:
t.join()
print(eggs)
if __name__ == '__main__':
main()
输出:
[1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5]
有时候,放入的顺序会发生混乱,但是此例逻辑太简单,没有发生混乱。因此可以让子程序随机休眠一段时间:
"""
同步原语:锁
"""
import threading
import time
import random
eggs = []
def put_egg(n, lst):
for i in range(1, n+1):
# 休眠子程序,造成混乱
time.sleep(random.randint(0, 2))
# 放入数据时,显示该数据是由哪个子线程放入的
lst.append(str(i) + '-' + threading.current_thread().name)
def main():
threads = []
for i in range(3):
t = threading.Thread(target=put_egg, args=(5, eggs))
threads.append(t)
for t in threads:
t.start()
for t in threads:
t.join()
print(eggs)
if __name__ == '__main__':
main()
输出:
['1-Thread-1', '1-Thread-2', '1-Thread-3', '2-Thread-2', '3-Thread-2', '4-Thread-2', '5-Thread-2', '2-Thread-1', '2-Thread-3', '3-Thread-3', '3-Thread-1', '4-Thread-3', '5-Thread-3', '4-Thread-1', '5-Thread-1']
可以看到,已经产生混乱。加入同步锁:
"""
同步原语:锁
"""
import threading
import time
import random
eggs = []
# 引入同步锁
lock = threading.Lock()
def put_egg(n, lst):
# 获得同步锁
lock.acquire()
for i in range(1, n+1):
# 休眠子程序,造成混乱
time.sleep(random.randint(0, 2))
# 放入数据时,显示该数据是由哪个子线程放入的
lst.append(str(i) + '-' + threading.current_thread().name)
# 释放同步锁
lock.release()
def main():
threads = []
for i in range(3):
t = threading.Thread(target=put_egg, args=(5, eggs))
threads.append(t)
for t in threads:
t.start()
for t in threads:
t.join()
print(eggs)
if __name__ == '__main__':
main()
输出:
['1-Thread-1', '2-Thread-1', '3-Thread-1', '4-Thread-1', '5-Thread-1', '1-Thread-2', '2-Thread-2', '3-Thread-2', '4-Thread-2', '5-Thread-2', '1-Thread-3', '2-Thread-3', '3-Thread-3', '4-Thread-3', '5-Thread-3']
支持上下文操作:
"""
同步原语:锁
"""
import threading
import time
import random
eggs = []
# 引入同步锁
lock = threading.Lock()
def put_egg(n, lst):
# 获得同步锁
# lock.acquire()
# 支持上下文操作
with lock:
for i in range(1, n+1):
# 休眠子程序,造成混乱
time.sleep(random.randint(0, 2))
# 放入数据时,显示该数据是由哪个子线程放入的
lst.append(str(i) + '-' + threading.current_thread().name)
# 释放同步锁
# lock.release()
def main():
threads = []
for i in range(3):
t = threading.Thread(target=put_egg, args=(5, eggs))
threads.append(t)
for t in threads:
t.start()
for t in threads:
t.join()
print(eggs)
if __name__ == '__main__':
main()
输出:
['1-Thread-1', '2-Thread-1', '3-Thread-1', '4-Thread-1', '5-Thread-1', '1-Thread-2', '2-Thread-2', '3-Thread-2', '4-Thread-2', '5-Thread-2', '1-Thread-3', '2-Thread-3', '3-Thread-3', '4-Thread-3', '5-Thread-3']
25_5.qunue队列
实例:
import time
import threading
import random
import queue
"""
LIFO队列示例
"""
def procuder(data_queue):
for i in range(5):
time.sleep(0.5)
item = random.randint(1, 100)
# 在队列中放入产生的随机数
data_queue.put(item)
print('线程{}在队列中放入了{}'.format(threading.current_thread().name, item))
def comsumer(data_queue):
while True:
try:
# 获取数据项
item = data_queue.get(timeout = 3)
print('线程{}在队列中移除了{}'.format(threading.current_thread().name, item))
except queue.Empty:
# 如果队列为空,则跳出循环
break
else:
# 声明当前队列任务处理完毕
data_queue.task_done()
def main():
# 产生队列
q = queue.Queue()
threads = []
# 创建子线程,执行producer子程序
p = threading.Thread(target=procuder, args=(q, ))
p.start()
for i in range(2):
# 创建子线程,执行comsumer子程序
c = threading.Thread(target=comsumer, args=(q, ))
threads.append(c)
for i in threads:
i.start()
for i in threads:
i.join()
# 队列所有项处理完毕前阻塞
q.join()
if __name__ == '__main__':
main()
输出:
线程Thread-1在队列中放入了58
线程Thread-2在队列中移除了58
线程Thread-1在队列中放入了51
线程Thread-3在队列中移除了51
线程Thread-1在队列中放入了99
线程Thread-2在队列中移除了99
线程Thread-1在队列中放入了77
线程Thread-3在队列中移除了77
线程Thread-1在队列中放入了83
线程Thread-2在队列中移除了83
25_6.multiprocessing多进程模块
import multiprocessing
import time
"""
多进程示例
"""
def func(n):
print(f'{multiprocessing.current_process().name}执行开始于:{time.ctime()}')
time.sleep(n)
print(f'{multiprocessing.current_process().name}执行结束于:{time.ctime()}')
def main():
print(f'主函数执行开始于:{time.ctime()}')
processess = []
p1 = multiprocessing.Process(target=func, args=(3, ))
processess.append(p1)
p2 = multiprocessing.Process(target=func, args=(2, ))
processess.append(p2)
for i in processess:
i.start()
for i in processess:
i.join()
print(f'主函数执行开始于:{time.ctime()}')
if __name__ == '__main__':
main()
输出:
主函数执行开始于:Tue Feb 25 11:33:55 2020
Process-1执行开始于:Tue Feb 25 11:33:55 2020
Process-2执行开始于:Tue Feb 25 11:33:55 2020
Process-2执行结束于:Tue Feb 25 11:33:57 2020
Process-1执行结束于:Tue Feb 25 11:33:58 2020
主函数执行开始于:Tue Feb 25 11:33:58 2020
25_7.更多并行编程
实例:
import time
import concurrent.futures
"""
concurrent.futures实例
"""
numbers = list(range(1, 11))
def count(n):
for i in range(10000000):
i += i
return i * n
def worker(x):
result = count(x)
print(f'{x}的计算结果是:{result}')
# 顺序执行
def sequential_execution():
start_time = time.clock()
for i in numbers:
worker(i)
print(f'顺序执行总共花费时间是:{time.clock() - start_time}秒')
# 线程池执行
def threading_execution():
start_time = time.clock()
with concurrent.futures.ThreadPoolExecutor(max_workers = 5) as executor:
for i in numbers:
executor.submit(worker, i)
print(f'线程池执行总共花费时间是:{time.clock() - start_time}秒')
# 进程池执行
def process_execution():
start_time = time.clock()
with concurrent.futures.ProcessPoolExecutor(max_workers = 5) as executor:
for i in numbers:
executor.submit(worker, i)
print(f'进程池执行总共花费时间是:{time.clock() - start_time}秒')
if __name__ == '__main__':
# 顺序执行
sequential_execution()
顺序执行时,输出:
1的计算结果是:19999998
2的计算结果是:39999996
3的计算结果是:59999994
4的计算结果是:79999992
5的计算结果是:99999990
6的计算结果是:119999988
7的计算结果是:139999986
8的计算结果是:159999984
9的计算结果是:179999982
10的计算结果是:199999980
顺序执行总共花费时间是:9.175301117秒
若改为进程池执行:
if __name__ == '__main__':
# 顺序执行
# sequential_execution()
# 线程池执行
threading_execution()
输出:
2的计算结果是:39999996
1的计算结果是:19999998
3的计算结果是:59999994
4的计算结果是:79999992
5的计算结果是:99999990
7的计算结果是:139999986
6的计算结果是:119999988
8的计算结果是:159999984
10的计算结果是:199999980
9的计算结果是:179999982
线程池执行总共花费时间是:8.921216853999999秒
若改为进程池执行:
if __name__ == '__main__':
# 顺序执行
# sequential_execution()
# 线程池执行
# threading_execution()
# 进程池执行
process_execution()
输出:
4的计算结果是:79999992
1的计算结果是:19999998
5的计算结果是:99999990
2的计算结果是:39999996
3的计算结果是:59999994
6的计算结果是:119999988
9的计算结果是:179999982
10的计算结果是:199999980
7的计算结果是:139999986
8的计算结果是:159999984
进程池执行总共花费时间是:5.669219574秒
26_4.类定义装饰器
使用函数定义一个装饰器:
"""
函数定义装饰器
"""
def p_decorator(func):
def wrapper(*args, **kwargs):
return '<p>' + func() + '</p>'
return wrapper
@p_decorator
def get_text():
return '欢迎欢迎!'
if __name__ == '__main__':
print(get_text())
输出:
<p>欢迎欢迎!</p>
也可以:
"""
函数定义装饰器
"""
def p_decorator(func):
def wrapper(*args, **kwargs):
return '<p>' + func(*args, **kwargs) + '</p>'
return wrapper
# @p_decorator
def get_text():
return '欢迎欢迎!'
if __name__ == '__main__':
html = p_decorator(get_text)
print(html())
输出:
<p>欢迎欢迎!</p>
26_4.类定义装饰器
实例:
"""
类定义装饰器
"""
class P:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
return '<p>' + self.func(*args, **kwargs) + '</p>'
@P
def get_text():
return '欢迎欢迎!'
@P
def get_upper_text(text):
return text.upper()
if __name__ == '__main__':
print(get_text())
print(get_upper_text('asdfghjkl'))
输出:
<p>欢迎欢迎!</p>
<p>ASDFGHJKL</p>
尝试将函数定义的装饰器作用在类中:
"""
函数定义装饰器
"""
def p_decorator(func):
def wrapper(*args, **kwargs):
return '<p>' + func(*args, **kwargs) + '</p>'
return wrapper
class Student:
def __init__(self, name):
self.name = name
@p_decorator
def get_name(self):
return self.name
# @p_decorator
def get_text():
return '欢迎欢迎!'
if __name__ == '__main__':
# html = p_decorator(get_text)
# print(html())
s = Student('mike')
print(s.get_name())
输出:
<p>mike</p>
尝试将类定义的装饰器作用于类上:
"""
类定义装饰器
"""
class P:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
return '<p>' + self.func(*args, **kwargs) + '</p>'
class Student:
def __init__(self, name):
self.name = name
@P
def get_name(self):
return self.name
@P
def get_text():
return '欢迎欢迎!'
@P
def get_upper_text(text):
return text.upper()
if __name__ == '__main__':
# print(get_text())
# print(get_upper_text('asdfghjkl'))
s = Student('mike')
print(s.get_name())
发现会报错。说明函数定义的装饰器通用性较好。函数定义的装饰器既可以作用与普通函数,也可以作用与类。类定义的装饰器只能作用与普通函数,不能作用于类。
26_5.参数化装饰器
实例:
"""
参数化装饰器
"""
# 定义参数化装饰器
def tag(tag):
def tag_decorator(func):
def wrapper(*args, **kwargs):
return f'<{tag}>' + func(*args, **kwargs) + f'</{tag}>'
return wrapper
return tag_decorator
class Student:
def __init__(self, name):
self.name = name
@tag('div')
@tag('pp')
def get_name(self):
return self.name
# @p_decorator
def get_text():
return '欢迎欢迎!'
if __name__ == '__main__':
# html = p_decorator(get_text)
# print(html())
s = Student('mike')
print(s.get_name())
输出:
<div><pp>mike</pp></div>