python中的多线程多进程

并发编程

  • 并发
    • 同时有很多事要做,可以并行处理也可以串行处理
  • 并行

    • 同时做多件事
    并发模块
    • threading模块
      • 线程也叫轻量级进程,它是一个基本的CPU单元,也是程序执行过程中的最小单位。
    • multiprocessing模块
      • 进程就是一个程序在一个数据集上的一次动态执行的过程。进程一般有程序、数据集、进程控制块三部分组成。
    • 进程和线程的关系
      • 线程是属于进程的
      • 线程是运行在进程空间内
      • 进程运行时会有系统资源的调度,而进程不需要调度资源,因此进程的启动会比线程快。
    基于线程的并行-关键函数
    • 创建线程的两种方法
      • 创建一个函数
      • 继承thread类
      • Thread是threading模块中最重要的类之一,可以使用它来创建一个线程
    • 函数调用线程
    • 构造方法:
      Tread(group = None, target = None,name=None,args=(),kwargs={})
      • group:线程组,目前还没有实现,库引用中提示必须是None
      • target:要执行的方法
      • name:线程名
      • args/kwargs:要传入方法的参数
    • thread的方法说明名
      • isAlive():返回线程是否在运行。正在运行指启动后、终止前。
      • get/setName(name):获取/设置线程名
      • t.start() 启动线程
      • t.join() 逐个执行每个线程,执行完毕后继续往下执行
        另一种说法 join([timeout]):阻塞当前上下文环境的线程,知道调用此方法的线程终止或达到指定的timeout.(可选参数)
      • t.run() 线程被cpu调度后,自动执行线程对象的run方法
      • Daemon后台线程:默认False
      • (其他论坛版本)is/setDaemon(bool):获取/设置是后台线程(默认是前台线程(False))。(在start前设置)
        • 如果后台线程,主线程执行过程中,后台线程也在进行,主线程完毕后,后台线程不论成功与否,主线程和后台线程均停止
        • 如果是前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,程序停止
    创建线程-创建函数
    import threading
    import time
    
    def counter(n):
        cnt = 0;
        for i in xrange(n):
            cut += 1
            time.sleep(0.1)
            print cnt
    
    th = threading.Thread(target = counter, args=(10,));
    th.start()
    th.join()
    print 'main thread task done'
    
    创建线程-继承类
    import threading, time, random
    
    def counter():
        cnt = 0;
        for i in xrange(10000):
            for j in xrange(i):
                cnt += j;
    
    class SubThread(threading.Thread):
        def __init__(self,name):
            threading.Thread.__init__(self,name=name);
                pass
    
        def run(self):
            i = 0;
            while i < 3:
                print self.name, 'counting...\n';
                counter()
                print self.name,'finish\n'
                i += 1;
    
    th = SubThread('thread-1');
    th.start();
    th.join();
    print 'all done'
    

  th.setDaemon(False)   ---- 表示令th这个子进程为不重要进程,
  那么主进程就不必等待这个th子进程执行完才去继续执行,可以在th没有执行完主进程
  就开始执行。

threading模块提供的线程同步原语包括:
  • Lock
  • RLock
  • Condition
  • Event
  • Semaphore等对象

    RLock

    acquire(wait=True) 此方法用来请求资源,如果资源没有被占用就调用资源且将资源设为被占用,如果资源已经被调用,那么使用此方法的线程就只能阻塞等待
    lock()对象, 用于判断这个资源是否上锁
    release() 这个方法是用于线程把占用的资源释放掉


线程同步(增加的为同步锁)
from threading import Lock, Thread
# lock = Lock
some_var = 0
class IncrementThread(Thread):
    def run(self):
        global some_var
        read_value = some_var
        print "some_var in %s is %d" %(self.name, read_value)
        # lock.acquire()
        some_var = read_value + 1


def use_increment_thread():
    threads = []
    for i in range(50):
        t = IncrementThread()
        threads.append(t)
        t.start()
    for t in threads:
        t.join()
    print "After 50 modifications, some_var should have become 50"
    print "After 50 modification, some_var is %d" % (some_var,)
use_increment_thread()

例:不加锁计数器(加锁保证)
import time
from threading import Thread, Lock
value = 0
lcok = Lock()
def getlock():
    # with lock:
    gloabal value
    new = value + 1
    time.sleep(0.001)
    value = new
threads = []
for i in range(1000):
    t = Thread(target=getlock)
    t.start()
    threads.append(t)
for t in threads:
    t.join()
print value
当资源为外部资源时
import threading
import time

def test_xc():
    mutex.acquire() #取得锁
    f = open("text.txt", "a")
    f.write("text_dxc" + '\n')
    f.close()
    mutex.release()  # 释放锁

mutex = threading.lock() #创建锁
threads = []
for i in xrange(5):
    t = threading.Thread(target=text_xc)
    t.start()
    threads.append(t)
for t in threads:
    t.join()

如果没有这个线程锁会出现什么情况

可重用锁

可重用锁

同步机制

items_cv.notify() 的作用是通知等待的进程,将其唤醒,例子如下:

import threading, time
class Hider(threading.Thread):
    def __init__(self, cond, name):
        super(Hider, self).__init__()
            self.cond = cond
            self.name = name
    def run(self):
        time.sleep(1)  # 确保先运行Seeker中的方法
        self.cond.acquire()
        print self.name + ': 我已经藏好了'
        self.cond.notify()
        self.cond.wait()

        print self.name + ':  被你找到了,哎~~~'
        self.cond.notify()
        self.cond.release()

class Seeker(threading.Thread):
    def __init__(self,cond,name):
        super(Seeker, self).__init__()
        self.cond = cond
        self.name = name
    def run(self):

        self.cond.acquire()
        self.cond.wait()  # 释放对锁的占用,同时线程挂起在这里,直到被notify并继续执行

        print self.name + ':我已经蒙好眼了,你藏吧~ '
        self.cond.notify()
        self.cond.wait()

        self.cond.release()
        print self.name + ':我赢了'
cond = threding.Condition()
seeker = Seeker(cond, 'seeker')
hider = Hider(cond, 'hider')
seeker.start()
hider.start()

同步机制-Event
  • 基于事件的同步机制
    • 一个线程发送/传递时间,另一个线程等待时间的触发。
  • 简单的线程通信机制
    • 他提供了设置信号,清除信号,等待等实现线程间的通信
  • 工作原理
    • Event对象和条件标记类似,允许线程等待某个事件发生。
    • 初始状态时事件被设置为0
    • 如果事件没有被设置而线程正在等待该事件,那么线程就会被阻塞直到事件被设置为止
    • 当有线程设置了这个事件时就会唤醒所有正在等待该事件的线程
    • 如果线程等待的该事件已经设置了,那么线程会继续执行
交通灯
improt threading
import random
import time

class VehicleThread(threading.Thread):
    """Class representing a motor vehicle at an intersection"""

    def __init__(self, threadName, event):
        """Initializes thread"""

        threading.Thread.__init__(self, name=threadName)
        self.threadEvent = event

    def run(self):
        """Vehicle waits unless/until light is green"""
        time.sleep(random.randrange(1,10))
        # print arrival time of car at intersection
        print "%s arrived at %s\n" % \
            (self.getName(), time.ctime(time.time())

        # wait for green light
        self.threadEvent.wait()

        # displays time that car departs intersection
        print "%s passes through intersection at %s\n" %\
            (self.getName(), time.ctime(time.time()))

greenLight = threading.Event()
vehicleThreads = []

# creates and starts five Vehicle threads
for i in rang(1, 5):
    vehicleThreads.append(VehicleThread("Vehicle" + str(i), greenLight))

for vehicle in vehicleThreads:
    vehicle.starts()

while threading.activeCount() >1:
    # sets the Event's flag to false -- block all incoming vehicles
    greenLight.clear()
    print "RED LiGHT! at", time.ctime(time.time())
    time.sleep(3)

    # sets the Event's flag to true -- awaken all waiting vehicles
    print "GREEN LIGHT! at", time.ctime(time.time())
    greenLight.set()
    time.sleep(1)

threading模块中常用的方法
  • thread.currentThread() :返回当前的线程变量
  • thread.enumerate():返回一个包含正在运行的线程的list。正在运行指程序启动后、结束前,不包括启动前和终止后的线程。
  • thread.activeCount():返回正在运行的线程数量,与len(thread.enumearte())由相同结果
thread模块提供的常量
  • thread.TIMEOUT_MAX设置thread全局超时时间
同步机制-信号量
  • 工作原理
    • 信号量通过一个计数器控制对共享资源的访问
    • 当此线程不再需要访问共享资源时
    • 它释放该通行证,这导致信号量的计数递增
    • 如果另一个线程等待通行证,则那个线程将在那时获得通行证
  • 操作:

    • 每当调用acquire()时,内置计数器-1
    • 每当调用release()时,内置计数器+1

      import time
      from random import random
      from threading import Thread, Semaphore
      sema = Semaphore(3)
      def foo(tid):
          with sema:   # 每次一个线程运行了with语句信号量就会减一
              print '{} acquire sema'.format(tid)
              wt = random()*2
              time.sleep(wt)
          print '{} release sema'.format(tid)
      threads = []
      for i in range(5):
          t = Thread(target=foo, args = (i,))
          threads.append(t)
          t.start()   
      fort t in threads:
          t.join()
      

GIL

基于进程的并行-简介
  • multiprocessing模块
    • Python中的多进程管理包
    • multiprocessing包中也有Lock/Event/Semaphore/Condition类
  • 用途
    • Python设计的限制
    • 最多只能用满1个CPU核心
    • 借助各个包,可以轻松的完成从单进程到并发执行的转换。
基于进程的并行-创建
  • 可以轻松完成从单进程到多进程并发执行的转换
  • multiprocessing支持子进程、通信和共享数据、执行不同形式的同步
  • 提供了Poccess、Queue、Pipe、Lock等组件。
  • Process([group [,target,[name [, args [, kwargs]]]]])
    • target表示调用对象,可以传入方法的名字
    • args表示被调用对象的位置参数元组
    • kwargs表示调用对象的字典
    • name是别名, 相当于给这个进程取一个名字
    • group分组, 实际上不使用

创建进程

import multiprocessing

def foo(i):
    print 'called funtion in process: %s' % i
    return 

Process_jobs = []
for i in range(5):
    p = multiprocessing.Process(target = foo, args=(i,))
    Process_jobs.append(p)
    p.start()
    p.join()
后台进程
继承创建进程
进程间的数据共享
  • 共享内存

    from multiprocessing import Process,  Value, Array
    
    def f(n, a):
        n.value = 3.1415927
        for i in range(len(a)):
            a[i] = -a[i]
    
    if __name__ ==  '__main__':
        num = Value('d', 0.0)
        arr = Array('i', range(10))
    
        p = Process(target=f, args=(num, arr))
        p.start()
        p.join()
    
        print num.value
        print arr[:] 
    
  • 进程共享队列

    • 消息队列
      • 提供了一种从一个进程向另一个进程发送数据块的方法。
      • 通过发送消息来避免命名管道的同步和阻塞问题。
    • multiprocessing当中的Queue使用方式

      • put操作,将对象放入Queue (放可以放多个)
      • get操作,将对象从Queue当中读出 (拿却只能拿一次)
      • Queue对象负责进程之间的对象传输

        import  multprocessing
        import random
        import time
        class producer(multiprocessing.Process):
            def __init__(self. queue):
                multiprocessing.Process.__init__(self)
                self.queue = queue
            def run(self):
                for i in range(10):
                    item =random.randint(0,256)
                    self.queue.put(item)
                    print ("Process Producer : item %d appended to queue %s" % (item, self.name)
                    time.sleep(1)
                    print ("The size of queue is %s" % self.queue.qsize())
        class consumer(multiprocessing.Process):
            def __init__(self, queue):
                multiprocessing.Process.__init__(self)
                self.queue = queue
            def run(self):
                while True:
                    if (self.queue.empty()):
                        print("the queue is empty")
                        break
                    else:
                        time.sleep(2)
                        item = self.queue.get()
                        print ('Process Consumer : item %d popped from by %s  \n'  %(item,self.name)
                time.sleep(1)
        
  • 管道通信

    • 管道,顾名思义,一端发一端收。
    • Pipe可以单向(half-duplex),也可以是双向(duplex)
    • 我们通过multiprocessing.Pipe(duplex=False)创建单向管道(默认为双向)
    • 一个进程从PIPE一端输入对象,然后被PIPE另一端的进程接收。
    • 单项管道只允许管道一端的进程输入
    • 双向管道则允许从两端输入

      from multiprocessing improt Process,Pipe
      
      class Consumer(Process):
          def __init__(self,pipe):
              Process.__init__(self)
              self.pipe = pipe
      
          def run(self):
              self.pipe.send("Consumer Words")
              print "Consumer Recevived:", self.pipe.recv()
      
      class Producer(Process):
          def __init__(self,pipe):
              Process.__init__(self)
              self.pipe = pipe
      
              def run(self):
                  print "Producer Received:", self.pipe.recv()
                  self.pipe.send("Producer Words")
      
      pipe = pipe()
      p = Producer(pip[0])
      c = Consumer(pip[1])
      p.daemon = c.daemon = True
      p.start()
      c.start()
      p.join()
      c.join()
      print "Ended!"
      

进程池

#阻塞方式
from multiprocessiong import Lock, Pool
import t

def function(index):
    print "Start Process", index
    time.sleep(3)
    print "End Process", index

pool = Pool(processes=3)
for i in xrange(4):
    pool.apply(function,(i,))
    # pool.apply_async(function,(i,))  非阻塞方式

print "Started process"
pool.close()
pool.join()
print "Subprocess done"

协程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值