Python基础知识学习-第12天

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>
发布了23 篇原创文章 · 获赞 0 · 访问量 409

猜你喜欢

转载自blog.csdn.net/Mr_Wang0120/article/details/104462221