【Python】Python多任务第2篇:多线程、多进程与协程的代码实现范例

本期任务:介绍Python的多任务及其实现范例

【Python】Python多任务第1篇:多进程、多线程与协程通俗易懂的理解方式

【Python】Python多任务第2篇:多线程、多进程与协程的代码实现范例

完整GitHub代码:MultiTasking


一、多线程实现

  • 创建多线程任务
  • 共享全局变量
import threading
import time

# 全局变量 ---------------------------------------------------------------------------------------------------
g_num = 0

# 互斥锁 ----------------------------------------------------------------------------------------------------
mutex = threading.Lock()


# 待执行的多任务 --------------------------------------------------------------------------------------------
def test1(num):
    global g_num
    for i in range(num):
        mutex.acquire()  # 上锁
        g_num += 1
        mutex.release()  # 解锁

    print("---test1---g_num=%d" % g_num)


def test2(num):
    global g_num
    for i in range(num):
        mutex.acquire()  # 上锁
        g_num += 1
        mutex.release()  # 解锁

    print("---test2---g_num=%d" % g_num)


if __name__ == "__main__":
    # 创建2个线程,让他们各自对g_num加1000000次
    p1 = threading.Thread(target=test1, args=(1000000,))
    p1.start()

    p2 = threading.Thread(target=test2, args=(1000000,))
    p2.start()

    # 等待计算完成
    while len(threading.enumerate()) != 1:
        time.sleep(1)

    print("2个线程对同一个全局变量操作之后的最终结果是:%s" % g_num)


二、多线进程实现

普通多进程

  • 创建多进程任务
  • 使用队列进行进程通信(共享全局变量)
import multiprocessing

"""
一个进程向Queue中写入数据,另外一个进程从Queue中获取数据,
通过Queue完成了 多个需要配合的进程间的数据共享,从而能够 起到 解耦的作用
"""
def download_from_web(q):
    """下载数据"""
    # 模拟从网上下载的数据
    data = [11, 22, 33, 44]

    # 向队列中写入数据
    for temp in data:
        q.put(temp)

    print("---下载器已经下载完了数据并且存入到队列中----")


def analysis_data(q):
    """数据处理"""
    waitting_analysis_data = list()
    # 从队列中获取数据
    while True:
        data = q.get()
        waitting_analysis_data.append(data)

        if q.empty():
            break

    # 模拟数据处理
    print(waitting_analysis_data)

def main():
    # 1. 创建一个队列
    q = multiprocessing.Queue()

    # 2. 创建多个进程,将队列的引用当做实参进行传递到里面
    p1 = multiprocessing.Process(target=download_from_web, args=(q,))
    p2 = multiprocessing.Process(target=analysis_data, args=(q,))
    p1.start()
    p2.start()


if __name__ == "__main__":
    main()
 

使用进程池

  • 创建进程池实现多任务
  • 使用Manager中的Queue行进程通信(共享全局变量)
# 修改import中的Queue为Manager
import os
import time
from multiprocessing import Manager, Pool


def reader(q):
    print("reader启动(%s),父进程为(%s)" % (os.getpid(), os.getppid()))
    for i in range(q.qsize()):
        print("reader从Queue获取到消息:%s" % q.get(True))


def writer(q):
    print("writer启动(%s),父进程为(%s)" % (os.getpid(), os.getppid()))
    for i in "itcast":
        q.put(i)


if __name__ == "__main__":
    print("(%s) start" % os.getpid())
    q = Manager().Queue()  # 使用Manager中的Queue
    po = Pool()
    po.apply_async(writer, (q,))

    time.sleep(1)  # 先让上面的任务向Queue存入数据,然后再让下面的任务开始从中取数据

    po.apply_async(reader, (q,))
    po.close()
    po.join()
    print("(%s) End" % os.getpid())


三、协程

  • 使用第三方库gevent进行协程操作(使用豆瓣源加速安装)
    • pip install -i https://pypi.douban.com/simple gevent
  • 使用gevent.monkey将程序中用到的耗时操作的代码,换为gevent中自己实现的模块
from gevent import monkey
import gevent
import random
import time

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

def coroutine_work(coroutine_name):
    for i in range(10):
        print(coroutine_name, i)
        time.sleep(random.random())

gevent.joinall([
    gevent.spawn(coroutine_work, "work1"),
    gevent.spawn(coroutine_work, "work2")
])
原创文章 36 获赞 32 访问量 2749

猜你喜欢

转载自blog.csdn.net/weixin_43868754/article/details/105342461