Python学习第十二天---并行编程

1、并行编程:

概念的讲解

   首先了解一下什么是非并发编程: 程序由单个步骤序列构成。是一个包含独立子任务的程序执行性能低

   概念:异步、高效,分解子任务、简化流程与逻辑。

  进程 : process :就是一个程序的执行实例。每个进程都有自己的地址空间、内存、数据栈及辅助数据。

  线程 :thread:同一个进程内,可被并行激活的控制流,线程共享相同上下文(可用空间,数据结构)。
      特点:便于信息共享和通信 , 缺点是线程访问顺序差异导致结果不一致(条件 race condition)。

 Python GIL全局解释器锁(Global Interpreter Lock):python代码由虚拟机(解释器主循环)控制,主循环同时只能有一个控制线程执行,

 

2、多线程Thread

  单线程的运行:

#coding=gbk
import time
def worker(n):
    print("函数开始于:{0}".format(time.ctime()))
    time.sleep(n)
    print("函数结束于:{0}".format(time.ctime()))


if __name__ == '__main__':
   worker(10)

多线程的使用_thread 。python已经不推荐使用了:特点,没有控制进程结束机制。只有一个同步原语(锁),功能少于theading 。.start_new_thread开始线程

#coding=gbk
import  time
import  _thread
def worker(n):
    print("函数开始于:{0}".format(time.ctime()))
    time.sleep(n)
    print("函数结束于:{0}".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()

 这里面的time,sleep(6) 的时间是可以跳整的! 如果不写这个让线程睡上几秒的话! 会首先输出主函数结束于,因为我们的线程跟主函数的结束是没有关系的! 然后想要按照将woker中的都打印出来!必须time.sleep()的时候要跟上面线程的最大时间保持一致或者是大于, 但是身为开发人员我们并不知道他会在哪个时间线程结束!所以这个时间就不确定了!我们可以使用线程锁的概念来完成上面的需求。线程锁的代码在第四节上面展示。 下面介绍我们python中推荐使用的模块。

 

3、threading模块

    1、第一种构造:使用  .thread(target = 目标函数 , args = (参数1,参数2,.....)) 线程类比较直观的构造。

 threading.current_thread().name 获取当前线程的名称。

#coding=gbk
import  time
import  threading
"""threading.Thread() 实现多线程
"""
def worker(n):
    print("函数开始于:{0}".format(time.ctime()))
    time.sleep(n)
    print("函数结束于:{0}".format(time.ctime()))

def main():
    print('主函数执行开始于:{}'.format(time.ctime()))
    # _thread.start_new_thread(worker,(4,))
    # _thread.start_new_thread(worker,(2,))

    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()  # 这个join就是等待我们的子线程结束,
    print('主函数执行结束于:{}'.format(time.ctime()))

if __name__ == '__main__':
    main()
"""output:
主函数执行开始于:Mon Dec  3 20:32:56 2018
函数开始于:Mon Dec  3 20:32:56 2018
函数开始于:Mon Dec  3 20:32:56 2018
主函数执行结束于:Mon Dec  3 20:32:56 2018
函数结束于:Mon Dec  3 20:32:58 2018
函数结束于:Mon Dec  3 20:33:00 2018
"""
#可以看出来当主函数结束的时候!线程并没有结束运行。
#也就是当子线程还没有执行完的时候,我们的主线程就执行完毕了。
#这是因为我们的主线程跟子线程并没有进行同步。

 3、2:第二种方式:使用threading.Thread 派生类实现多线程。

#coding=gbk
import  time
import  threading
"""threading.Thread() 派生类实现多线程
"""
def worker(n):
    print("函数开始于:{0}".format(time.ctime()))
    time.sleep(n)
    print("函数结束于:{0}".format(time.ctime()))

#定义自己得派生线程类
class MuThread(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,))

    threads = []
    # t1 = threading.Thread(target=worker,args=(4,))
    t1 =MuThread(worker,(4,))
    threads.append(t1)

    # t2 = threading.Thread(target=worker,args=(2,))
    t2 = MuThread(worker, (2,))
    threads.append(t2)
#这样是我们的子线程还没有结束,主线程就结束的
    for t in threads:
        t.start()

 # 实现我们的主线程等待子线程运行结束的时候在停止运行。
    for t in threads:
        t.join()  # 这个join就是等待我们的子线程结束,
    print('主函数执行结束于:{}'.format(time.ctime()))

if __name__ == '__main__':
    main()

4、同步原语(锁)的学习

    为什么要用同步锁,我们举一个放鸡蛋的例子!三个人去放很多鸡蛋,会出现重复的现象!

人就代表我们的线程,这个时候我们就需要用到同步原语中的同步锁!

#coding=gbk
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(i)
    # 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()

这就是拿鸡蛋的一个操作!但是加锁以后相应的会降低性能。

 

5、queue队列的学习

    queue 模块下面的。 先进先出队列  FIFO ,
                                     还有一种后进先出的队列  就是 LIFO , 其他语言的栈。
                                     还有一个PriorityQueue 优先队列。 

看一个fifo的队列。

#coding=gbk
import threading
import queue
import time
import random

#创建一个生产者
def produce(date_queue):
    for i in  range(5):
        time.sleep(0.5)
        item = random.randint(1,100)
        date_queue.put(item)
        print('{}在队列汇总放入数据项:{}'.format(threading.current_thread().name,item))

#定义一个消费者
def consumer(date_queue):
    while True:
        try:
            item = date_queue.get(timeout=3)
            print('{}从对列中移除了{}'.format(threading.current_thread().name,item))
        except queue.Empty:
            break
        else:
            date_queue.task_done()

def main():
    q = queue.Queue()

    threads = []
    p =  threading.Thread(target=produce,args=(q,))
    p.start()

    for i in range(2):
        c = threading.Thread(target=consumer,args=(q,))
        threads.append(c)
    for t in threads:
        t.start()

    for t in threads:
        t.join()

    q.join()

if __name__ == '__main__':
    main()

 

6、multiprocessing多进程模块:充分运用多核、多cpu的计算能力,适用于计算密集型任务。使用是跟多线程一致的

7、更多的并行编程:concurrent.futures 模块。他主要在模块下给我准备两个模块,一个线程池的模块,ThreadPoolExecutor。还有一个ProcessPoolExecutor:多进行的模块。

#coding=gbk
import time
import concurrent.futures
"""  concurrent.futures模块的学习。
"""
number = list(range(1,11))
def count(n):
    for i in range(1000000):
        i += i
    return i * n

def worker(x):
    result = count(x)
    print("数字:{}的计算结果是:{}".format(x,result))

#顺序执行
def sequential_execution():
    start_time = time.clock()
    for i in number:
        worker(i)
    print('顺序执行花肥时间:{}秒'.format(time.clock() - start_time))

#线程池执行
def threading_execution():
    start_time = time.clock()
    with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
        for i in number:
            executor.submit(worker,i)
    print('线程池的花费时间:{}'.format(time.clock() - start_time))

#多进程去执行
def process_excution():
    start_time = time.clock()
    with concurrent.futures.ProcessPoolExecutor(max_workers=5) as executer:
        for i in number:
            executer.submit(worker,i)
    print('进程池执行花费的时间为:{}'.format(time.clock() - start_time))

if __name__ == '__main__':
    #sequential_execution() #顺序执行花肥时间:0.6267245815110348秒
    #threading_execution()   #线程池的花费时间:0.5682613913639004
    #process_excution()      #进程池执行花费的时间为:0.558646438043795

上面是三种方式的比较!实际工作中,你的任务是计算密集型的时候,首先多进程,如果是IO密集型的!方便随时释放,我们使用多进程。

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看READme.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 、 1资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看READmE.文件(md如有),本项目仅用作交流学习参考,请切勿用于商业用途。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值