并行程序-线程(二)

生产者与消费者模式

在线程世界中,生产者即产生数据的线程,消费者即使用数据的线程,在使用多线程的时候,生产者和消费者处理数据的速度不一定一样,如果生产者处理数据的速度比消费者处理数据的速度快,那么生产者必须等消费者处理完数据才能继续生产,相反,如果生产者处理数据的速度比消费者处理数据的速度慢,那么消费者必须等待生产者。为了解决等待问题,引入了生产者消费者模式。


生产者和消费者之间通过一个队列来解决强耦合问题,生产者将数据添加到队列中,消费者从队列中使用数据,两者不直接通讯。这个队列是用来给生产者和消费者解耦的。
和进程不同的是,进程中使用队列用于进程间通信:from multiprocessing import Queue
线程中使用队列:from queue import queue(python3中);
from queue import queue(python2中)
不过,进程和线程中关于Queue的所有操作都是一样的,即put,get,qsize,full,empty等。

# encoding=utf-8

import threading
import time

#python2中
#from Queue import Queue

#python3中
from queue import Queue

class Producer(threading.Thread):
    def run(self):
        global queue
        count = 0
        while True:
            if queue.qsize() < 1000:
                for i in range(100):
                    count = count +1
                    msg = '生成产品'+str(count)
                    queue.put(msg)
                    print(msg)
            time.sleep(0.5)

class Consumer(threading.Thread):
    def run(self):
        global queue
        while True:
            if queue.qsize() > 100:
                for i in range(3):
                    msg = self.name + '消费了 '+queue.get()
                    print(msg)
            time.sleep(1)


if __name__ == '__main__':
    queue = Queue()

    for i in range(500):
        queue.put('初始产品'+str(i))
        # 两个生产者
    for i in range(2):
        p = Producer()
        p.start()
        # 五个消费者
    for i in range(5):
        c = Consumer()
        c.start()

threadLocal对象在线程中的使用

# coding=utf-8

import threading

# 创建全局ThreadLocal对象:
local_school = threading.local()

def process_student():
    # 获取当前线程关联的student:
    std = local_school.student
    print('Hello, %s (in %s)' % (std, threading.current_thread().name))

def process_thread(name):
    # 绑定ThreadLocal的student:
    local_school.student = name
    process_student()

t1 = threading.Thread(target= process_thread, args=('dongGe',), name='Thread-A')
t2 = threading.Thread(target= process_thread, args=('老王',), name='Thread-B')
t1.start()
t2.start()

异步

同步:你喊你朋友吃饭 ,你朋友在忙 ,你就⼀直在那等,等你
朋友忙完了 ,你们⼀起去。
异步:你喊你朋友吃饭,你朋友在忙,便告诉你:你先去忙,等我这边结束了去找你。
异步的好处是,当使用多进程时,主进程不需要一直等待子进程结束,可以先去做自己的事情,当子进程结束的时候操作系统会告诉主进程,子进程已结束,然后主进程会停下手中的任务转而去做操作系统安排的任务。

# coding=utf-8

from multiprocessing import Pool
import time
import os

def test():
    print("---进程池中的进程---pid=%d,ppid=%d--"%(os.getpid(),os.getppid()))
    for i in range(3):
        print("----%d---"%i)
        time.sleep(1)
    return "hahah"

def test2(args):
    print("---callback func--pid=%d"%os.getpid())
    print("---callback func--args=%s"%args)


if __name__=="__main__":
    pool = Pool(3)
    pool.apply_async(func=test,callback=test2)

    #异步的理解:主进程正在做某件事情,突然 来了一件更需要立刻去做的事情,
    #那么这种,在父进程去做某件事情的时候 并不知道是什么时候去做,的模式 就称为异步
    while True:
        time.sleep(1)
        print("----主进程-pid=%d----"%os.getpid())


# ---进程池中的进程---pid=14912,ppid=14776--
# ----0---
# ----主进程-pid=14776----
# ----1---
# ----主进程-pid=14776----
# ----2---
# ----主进程-pid=14776----
# ---callback func--pid=14776
# ---callback func--args=hahah
# ----主进程-pid=14776----
# ----主进程-pid=14776----
# ----主进程-pid=14776----
# ----主进程-pid=14776----

GIL

GIL,全局解释器锁,作用是限制多线程同时执行,保证同一时间内只有一个线程在执行。那为什么要这么做呢?因为对于多线程而言,全局变量是共享的,为了线程的安全,需要保证同一时刻只有一个线程在工作,因此在单核或多核处理器中,多线程并不能并行,只是并发而已,不能提高效率,反而多线程执行一个程序所用时间可能比单线程还要多,因为操作系统不断调度各个线程浪费了时间。
那我们说的多线程提高效率指的是什么?多线程提高效率,不如说是提高了CPU的执行时间,即减少了等待时间。
并发,指的是一个处理器同时处理多个任务,并行指的是多个处理器同时处理多个任务,就好比一个人同时吃三个馒头和三个人吃三个馒头,并发的时间肯定是并行的三倍。
那么解决多线程效率的方案有哪些?

  1. 在需要并行的地方用C语言写
  2. 能用进程就不用线程
  3. 将cpython解释器换jpython,因为 GIL只有cpython解释器。

猜你喜欢

转载自blog.csdn.net/Albert_Ejiestein/article/details/84445052
今日推荐