Python全栈开发:线程代码实例

#进程与线程的关系
"""
多进程(主进程,子进程):
    优点:能同时利用多个CPU,进行多个操作,提高效率。
    缺点:耗费内存资源(进程要开辟内存空间),进程不是越多越好,CPU个数 = 进程个数。
    注意:进程创建内存空间,线程共享内存空间,进程里有全局解释器锁,进程中一次只应许一个线程被处理。
    使用场景:计算密集型适合多进程。
多线程(主线程,子线程):
    优点:共享内存,IO操作时(不用CPU),创造并发操作(多个操作同时进行),提高效率。
    缺点:抢占资源,请求上下文切换非常耗时(线程处理切换后找到上次处理的地方),线程不是越多越好,视具体案例而定。
    注意:在计算机中,执行任务的最小单元就是线程。
    使用场景:IO密集型适合多线程。
"""
"""
队列queue
    先进先出,一边放,另一边取
    可设置最大个数,get等待,get_nowait不等待
"""
"""
使用线程
    1、创建线程
        import threading
        import time
        def f1():
            pass
        def f2(a1, a2):
            time.sleep(10)
            pass
        t = threading.Thread(target=f1, args=(11,22,33))
        t.start() # 线程开始跑,创建的是子线程
    2、线程锁
        防止出现脏数据,一个线程读取数据并对其加锁,CPU切换线程后其他线程不能读取数据,
    3、线程池
        Python内部没有提供线程池,需要自定义
"""
import threading
import time


def f1():
    pass


def f2(a1, a2):
    time.sleep(10)
    pass

t1 = threading.Thread(target=f2, args=(11, 22))
t1.setDaemon(True)  # 主线程是否等待子线程
t1.start()  # 线程开始跑,创建的是子线程
print("第一次等待中")
t1.join(2)  # 主线程等待子线程多久,不加参数无限等待
t2 = threading.Thread(target=f2, args=(11, 22))
t2.setDaemon(True)
t2.start()  # 线程开始跑,创建的是子线程
print("第二次等待中")
t2.join(2)  # 主线程等待子线程的执行的最多等待时间,超过时间,主线程继续执行下一部分
t3 = threading.Thread(target=f2, args=(11, 22))
t3.setDaemon(True)  # 主线程执行完(解释器执行代码),是否等待子线程执行完再关闭,True:不等待:False:等待。默认为False
t3.start()  # 线程开始跑,创建的是子线程

  线程event

#!/usr/bin/env python
# -*- coding;utf-8 -*-
"""
    线程event
"""
import threading
import time

def do(event):
    print("线程前半部分")
    event.wait()  # 阻塞(十字路口),红灯则等待,绿灯则继续执行
    print("线程后半部分")


event_obj = threading.Event()

for i in range(10):
    t = threading.Thread(target=do, args=(event_obj,))
    t.start()
# 耗时十分钟
# time.sleep(10)

event_obj.clear()  # 让灯变红
inp = input("请输入内容:>>>")
if inp == "true":
    event_obj.set()  # 让灯变绿,线程就都可以继续执行

  线程数据共享

#!/usr/bin/env python
# -*- coding;utf-8 -*-
"""
    默认情况下线程数据不共享
    线程与线程之间数据可以共享
"""
from threading import Thread
li = []


def foo(i):
    li.append(i)
    print("hello", li)

if __name__ == "__main__":
    for i in range(10):
        t = Thread(target=foo, args=(i,))
        t.start()

  线程池

  1. 简单线程池
    #!/usr/bin/env python
    # -*- coding;utf-8 -*-
    """
        自定义线程池博客园教程地址
            http://www.cnblogs.com/wupeiqi/articles/4839959.html
    """
    import queue
    import threading
    import time
    
    class ThreadPool(object):
    
        def __init__(self, max_num=20):
            self.queue = queue.Queue(max_num)
            for i in range(max_num):
                self.queue.put(threading.Thread)
    
        def get_thread(self):
            return self.queue.get()
    
        def add_thread(self):
            self.queue.put(threading.Thread)
    
    def func(i, arg):
        print(i)
        time.sleep(4)
        # 在队列中增加线程类
        arg.add_thread()
    
    if __name__ == "__main__":
        # 在队列中创建线程类
        pool = ThreadPool(10)
        for i in range(30):
            # 获得类
            thread = pool.get_thread()
            # 对象 = 类()
            ret = thread(target=func, args=(i, pool))
            ret.start()
  2. 高级线程池
    #!/usr/bin/env python
    # -*- coding;utf-8 -*-
    import threading
    import time
    import queue
    import contextlib
    StopEvent = object()
    
    class Threadpool(object):
    
        def __init__(self, max_num):
            self.max_num = max_num
            # 创建任务队列
            self.queue = queue.Queue()
            self.terminal = False
            # 表示真实创建的线程列表
            self.generate_list = []
            # 表示空闲的线程列表
            self.free_list = []
    
        def run(self, func, args, callback=None):
            """
            线程池执行一个任务
            :param func: 执行任务的函数
            :param args: 任务函数的参数(以元组形式存在的任务包,封装了几个参数)
            :param callback: 任务执行失败或者成功后执行的回调函数,回调函数有两个参数
            :return:
            """
            # 往任务队列里加任务
            w = (func, args, callback)
            self.queue.put(w)
            # 如果空闲线程等于零并且真实创建的线程数小于任务数
            if len(self.free_list) == 0 and len(self.generate_list) < self.max_num:
                self.generate_thread()
    
        def generate_thread(self):
            """
            创建一个线程
            :return:
            """
            t = threading.Thread(target=self.call)
            t.start()
    
        def call(self):
            """
            循环去获取任务函数并执行任务函数
            :return:
            """
            current_thread = threading.current_thread()
            self.generate_list.append(current_thread)
            # 去任务并执行
            event = self.queue.get()
            while event != StopEvent:
                # 如果是元组任务,解开任务包,执行任务
                func, args, callback = event
    
                try:
                    ret = func(*args)
                    success = True
                except Exception as e:
                    success = False
                    ret = e
    
                if callback is not None:
                    try:
                        callback(success, ret)
                    except Exception as e:
                        pass
                with self.work_station(self.free_list, current_thread):
                    if self.terminal:
                        event = StopEvent
                    else:
                        event = self.queue.get()
    
            else:
                self.generate_list.remove(current_thread)
    
        def close(self):
            # 中途终止线程
            num = len(self.generate_list)
            while num:
                self.queue.put(StopEvent)
                num -= 1
    
        def terminate(self):
            #  终止线程(不清空队列),线程一直在等待拿,程序不会退出
            """
            终止线程(清空队列)
                while self.generate_list:
                    self.queue.put(StopEvent)
            """
            self.terminate = True
            max_num = len(self.generate_list)
            # self.queue.empty()
            while max_num:
                max_num = len(self.generate_list)
                max_num -= 1
            #self.queue.empty()
    
        @contextlib.contextmanager
        def work_station(self, station, val):
            station.append(val)
            try:
                yield
            finally:
                station.remove(val)
    
    def work(i):
        # time.sleep(3)
        print(i)
    
    pool = Threadpool(10)
    for i in range(50):
        pool.run(func=work, args=(i,), callback=None)
    
    # pool.terminate()
    pool.close()
  3. 绝版线程池
    #!/usr/bin/env python
    # -*- coding;utf-8 -*-
    """
        自定义线程池博客园教程地址
            http://www.cnblogs.com/wupeiqi/articles/4839959.html
    """
    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.queue.clear()
    
        @contextlib.contextmanager
        def worker_state(self, state_list, worker_thread):
            """
            用于记录线程中正在等待的线程数
            """
            state_list.append(worker_thread)
            try:
                yield
            finally:
                state_list.remove(worker_thread)
    
    # How to use
    pool = ThreadPool(5)
    
    
    def callback(status, result):
        # status, execute action status
        # result, execute action return value
        pass
    
    def action(i):
        print(i)
    
    if __name__ == "__main__":
        for i in range(30):
            ret = pool.run(action, (i,), callback)
        time.sleep(0.01)  # 等待的时间xiao'l
        print(len(pool.generate_list), len(pool.free_list))
        print(len(pool.generate_list), len(pool.free_list))
        pool.close()  # 子线程结束时,主线程就结束,time.sleep后的内容可能没有结果
        # pool.terminate()
    

      

 

posted @ 2017-03-02 21:57  倪兴国  阅读(213)  评论(0编辑  收藏  举报