• python线程、线程池


    一、Python线程

    Threading用于提供线程相关的操作,线程是应用程序中工作的最小单元。

    1、创建线程

    1.1  自定义线程

    # 自定义线程
    import threading
    import time
    
    # 创建一个线程,继承threading.Thread
    class MyThread(threading.Thread):
        def __init__(self, num):
            threading.Thread.__init__(self)
            self.num = num
    
        # 每个线程执行的函数(任务)
        def run(self):
            print('running on number:%s ' % self.num)
            time.sleep(3)
    
    if __name__ == '__main__':
        for i in range(3):
            t1 = MyThread(i + 10)
            t2 = MyThread(i + 100)
            t1.start()
            t2.start()
    
    #----------- 输出结果---------------
        running on number:10 
        running on number:100 
        running on number:11 
        running on number:101 
        running on number:12 
        running on number:102 

    1.2  普通创建

    import threading
    import time
    # 全局变量
    gl_num = 0
    
    def show(arg):
        global gl_num
        time.sleep(1)
    
        gl_num += 1
        print(gl_num)
    
    for i in range(3):
        t = threading.Thread(target=show, args=(i, ))
        t.start()
    
    print('main thread stop')

    上述代码创建了3个“前台”线程,然后控制器就交给了CPU,CPU根据指定算法进行调度,分片执行指令。

    更多方法:

      • start              线程准备就绪,等待CPU调度
      • setName       为线程设置名称
      • getName       获取线程名称
      • setDaemon   设置为后台线程或前台线程(默认)
                             如果是后台线程,主线程执行过程中,后台线程也在进行,主线程执行完毕后,后台线程不论成功与否,均停止
                             如果是前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,程序停止
      • join               逐个执行每个线程,执行完毕后继续往下执行,该方法使得多线程变得无意义
      • run                线程被cpu调度后自动执行线程对象的run方法

    2、线程锁(Lock、RLock)

    由于线程之间是进行随机调度,并且每个线程可能只执行n条执行之后,当多个线程同时修改同一条数据时可能会出现脏数据,所以,出现了线程锁 - 同一时刻允许一个线程执行操作。

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import threading
    import time
    
    gl_num = 0
    
    def show(arg):
        global gl_num
        time.sleep(1)
        gl_num +=1
        print gl_num
    
    for i in range(10):
        t = threading.Thread(target=show, args=(i,))
        t.start()
    
    print 'main thread stop'
    未使用锁代码

    Python多线程同步Lock、RLock、Semaphore、Event实例

      Lock & RLock 用来确保多线程多共享资源的访问

      Semaphore用来确保一定资源多线程访问时的上限

      Event是最简单的线程间通信的方式

    一、多线程同步
    由于CPython的python解释器在单线程模式下执行,所以导致python的多线程在很多的时候并不能很好地发挥多核cpu的资源。大部分情况都推荐使用多进程。
    python的多线程的同步与其他语言基本相同,主要包含:
    Lock & RLock :用来确保多线程多共享资源的访问。
    Semaphore : 用来确保一定资源多线程访问时的上限,例如资源池。  
    Event : 是最简单的线程间通信的方式,一个线程可以发送信号,其他的线程接收到信号后执行操作。 
    二、实例
    1)Lock & RLock
    Lock对象的状态可以为locked和unlocked
    使用acquire()设置为locked状态;
    使用release()设置为unlocked状态。
    如果当前的状态为unlocked,则acquire()会将状态改为locked然后立即返回。当状态为locked的时候,acquire()将被阻塞直到另一个线程中调用release()来将状态改为unlocked,然后acquire()才可以再次将状态置为locked。
    Lock.acquire(blocking=True, timeout=-1),blocking参数表示是否阻塞当前线程等待,timeout表示阻塞时的等待时间 。如果成功地获得lock,则acquire()函数返回True,否则返回False,timeout超时时如果还没有获得lock仍然返回False。
    
    RLock与Lock的区别是:RLock中除了状态locked和unlocked外还记录了当前lock的owner和递归层数,使得RLock可以被同一个线程多次acquire()。
    lock&Rlock 理论知识

     RLock 锁实例

    # lock = threading.RLock()
    # lock = threading.Lock()
    # 互斥锁,同一时刻只允许一个线程执行操作
    import threading
    import time
    
    # 设置一个全局变量
    gl_num = 0
    
    # lock = threading.Lock()
    # 可以归执行锁操作,一般使用该锁
    lock = threading.RLock()
    
    def func():
        # 加锁
        lock.acquire()
        # 函数里要想修改全局变量,需要先声明
        global gl_num
        gl_num += 1
        time.sleep(1)
        print(gl_num)
        # 释放锁
        lock.release()
    
    for i in range(3):
        t = threading.Thread(target=func)
        t.start()
    
    print('main thread stop')

    信号量(Semaphore)

      Semaphore管理一个内置的计数器,每当调用acquire()时内置计数器-1;调用release() 时内置计数器+1;

      计数器不能小于0;当计数器为0时,acquire()将阻塞线程直到其他线程调用release()。

    Semaphore实例:(允许同一时间有五个线程同时运行)
    # 信号量(semaphore)
    import time, threading
    
    def run(n):
        # 信号量,加锁
        semaphore.acquire()
        time.sleep(1)
        print('run the thread: %s' % n)
        # 信号量,释放
        semaphore.release()
    
    if __name__ == '__main__':
        num = 0
        # 创建信号量,并且最多允许5个线程同时运行
        semaphore = threading.BoundedSemaphore(5)
        for i in range(20):
            t = threading.Thread(target=run, args=(i, ))
            t.start()
        print('main thread stop')

    事件(event)

      python线程的事件用于主线程控制其他线程的执行,事件主要提供了三个方法 set、wait、clear。

      Event内部包含了一个标志位,初始的时候为false。
      可以使用使用set()来将其设置为true;
      或者使用clear()将其从新设置为false;
      可以使用is_set()来检查标志位的状态;
      另一个最重要的函数就是wait(timeout=None),用来阻塞当前线程,直到event的内部标志位被设置为true或者timeout超时。如果内部标志位为true则wait()函数理解返回。

    event 实例:(当inp为true时才会执行print('execute'))
    # 事件(event)
    
    import threading
    
    def do(event):
        print('start')
        event.wait()
        print('execute')
    
    # 创建event对象
    event_obj = threading.Event()
    for i in range(2):
        t = threading.Thread(target=do, args=(event_obj, ))
        t.start()
    
    event_obj.clear()
    inp = input('>>>>>>:')
    if inp == 'true':
        event_obj.set()
    
    ----------输出结果----------
        start
        start
        >>>>>>:true
        execute
        execute

    条件(Condition)

      使得线程等待,只有满足某条件时,才释放n个线程

    Condition 实例

    # 条件(condition)
    
    import threading
    
    def run(n):
        con.acquire()
        con.wait()
        print('run the thread: %s' % n)
        con.release()
    
    if __name__ == '__main__':
        con = threading.Condition()
        for i in range(10):
            t = threading.Thread(target=run, args=(i, ))
            t.start()
    
        while True:
            inp = input('>>>>>>: ').strip()
            if inp == 'q':
                break
            con.acquire()
            con.notify(int(inp))
            con.release()
    
    # --------输出结果--------
        >>>>>>: 1
        >>>>>>: run the thread: 0
        2
        >>>>>>: run the thread: 2
        run the thread: 1

    wait_for()

    import threading
    def condition_func():
        ret = False
        inp = input('>>>>>>')
        if inp == '1':
            ret = True
        return ret
    
    def run(n):
        con.acquire()
        con.wait_for(condition_func)
        print('run the thread: %s' % n)
        con.release()
    
    if __name__ == '__main__':
        con = threading.Condition()
        for i in range(10):
            t = threading.Thread(target=run, args=(i, ))
            t.start()
    wait_for

    定时器 (Timer )

      定时器,指定n秒后执行某操作

    Timer  实例

    # Timer定时器
    from threading import Timer
    
    def hello():
        print('hello, world')
    
    def hi():
        print('hi, world')
    
    t = Timer(1, hello)
    t1 = Timer(2, hi)
    t.start()
    t1.start()
    
    -------输出结果---------
        hello, world
        hi, world

    线程池

    1、创建线程池

    # 自定义线程池
    import
    threading import queue import time class ThreadPool: def __init__(self, max_num=20): self.queues = queue.Queue(max_num) for i in range(max_num): self.queues.put(threading.Thread) def get_thread(self): return self.queues.get() def add_thread(self): self.queues.put(threading.Thread)
    # 设定线程池 最大线程数 pool
    = ThreadPool(5) def func(arg, p): print(arg) time.sleep(1) pool.add_thread() for i in range(30): thread = pool.get_thread() t = thread(target=func, args=(i, pool)) t.start() print('main thread stop')
    import queue
    import threading
    import contextlib
    import time
    
    StopEvent = object()
    
    class ThreadPool(object):
    
        def __init__(self, max_num, max_task_num = None):
            if max_task_num:
                self.q = queue.Queue(max_task_num)
            else:
                self.q = queue.Queue()
            self.max_num = max_num
            self.cancel = False
            self.terminal = False
            self.generate_list = []     #
            self.free_list = []
    
        def run(self, func, args, callback=None):
            """
            线程池执行一个任务
            :param func: 任务函数
            :param args: 任务函数所需参数
            :param callback: 任务执行失败或成功后执行的回调函数,回调函数有两个参数1、任务函数执行状态;2、任务函数返回值(默认为None,即:不执行回调函数)
            :return: 如果线程池已经终止,则返回True否则None
            """
            if self.cancel:
                return
            if len(self.free_list) == 0 and len(self.generate_list) < self.max_num:
                self.generate_thread()
            w = (func, args, callback,)
            self.q.put(w)
    
        def generate_thread(self):
            """
            创建一个线程
            """
            t = threading.Thread(target=self.call)
            t.start()
    
        def call(self):
            """
            循环去获取任务函数并执行任务函数
            """
            current_thread = threading.currentThread
            self.generate_list.append(current_thread)
    
            event = self.q.get()
            while event != StopEvent:
    
                func, arguments, callback = event
                try:
                    result = func(*arguments)
                    success = True
                except Exception as e:
                    success = False
                    result = None
    
                if callback is not None:
                    try:
                        callback(success, result)
                    except Exception as e:
                        pass
    
                with self.worker_state(self.free_list, current_thread):
                    if self.terminal:
                        event = StopEvent
                    else:
                        event = self.q.get()
            else:
    
                self.generate_list.remove(current_thread)
    
        def close(self):
            """
            执行完所有的任务后,所有线程停止
            """
            self.cancel = True
            full_size = len(self.generate_list)
            while full_size:
                self.q.put(StopEvent)
                full_size -= 1
    
        def terminate(self):
            """
            无论是否还有任务,终止线程
            """
            self.terminal = True
    
            while self.generate_list:
                self.q.put(StopEvent)
    
            self.q.empty()
    
        @contextlib.contextmanager
        def worker_state(self, state_list, worker_thread):
            """
            用于记录线程中正在等待的线程数
            """
            state_list.append(worker_thread)
            try:
                yield
            finally:
                state_list.remove(worker_thread)
    
    
    
    pool = ThreadPool(5)
    
    def callback(status, result):
        pass
    
    
    def action(i):
        print(i)
    
    for i in range(30):
        ret = pool.run(action, (i,), callback)
    
    time.sleep(5)
    print(len(pool.generate_list), len(pool.free_list))
    print(len(pool.generate_list), len(pool.free_list))
    # pool.close()
    # pool.terminate()
    线程池

    二、Python 进程

     

  • 相关阅读:
    三级菜单
    包的初识和进阶&异常处理
    常用模块一
    flask-script
    DBUtils
    Flask-WTForms
    Flask-SQLAchemy
    Flask
    scrapy-redis的使用和解析
    Django的信号;flask的信号;scrapy的信号;
  • 原文地址:https://www.cnblogs.com/yxy-linux/p/5685254.html
Copyright © 2020-2023  润新知