链条传动

砥砺前行,不忘初心!

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

基本使用

#!/usr/bin/env python
# -*- coding: utf-8 -*-

'''
一个应用程序,可以有多进程和多线程
默认情况下的程序都是单进程、单线程的

多进程、多线程目的是为了提高并发

python中:由于有GIL锁
多线程:适用于主要进行IO操作的程序
多进程:适用于主要进行CPU运算的程序
'''


import threading
import time

def f(arg):
    time.sleep(5)
    print(arg)

#创建一个线程
t1 = threading.Thread(target=f,args=(123,))   #target,表示子线程要执行的函数   args,表示函数的参数

#默认情况下主线程执行完毕后,如果子线程还没有执行完,主线程会等待子线程执行完成后才终止程序
#如果子线程创建后,设置了setDaemon(True),则主线程执行完毕后直接终止程序,不管子线程是否执行完成     ---默认是False
t1.setDaemon(True)

#启动线程(等待CPU调度,当cpu开始执行时,执行的是t1对象的run方法)
t1.start()

#默认情况下主线程创建了子线程后是不会等子线程执行完成的,而是直接往下执行
#如果子线程使用了join方法,则主线程执行到这里时,会一直等待子线程执行完成,才继续向下执行
# t1.join()
#jion方法还可以加参数,表示主线程执行到这里时最多等多长时间,如果子线程在该时间内执行完成,
# 主线程就继续向下执行,如果到了该时间后子线程还没执行完成,主线程也不再等待,继续向下执行
#t1.join(2)  #主线程执行到这里,最多等2秒,2秒内子线程执行完成,则主线程立即向下执行;如果2秒后子线程还没执行完成,则主线程不再等待,继续向下执行


print('end')

 

队列

#!/usr/bin/env python
# -*- coding: utf-8 -*-

'''
对列都是在内存中创建的,进程退出,则对列就没有了

一般队列:先进先出
'''

'''
import queue


#创建一个队列
# q = queue.Queue()
q = queue.Queue(2)   #对列加参数,表示对列最多存放2个数据

print(q.empty())  #判断对列是否为空,对列为空则返回True

#向对列中存放数据
q.put(11)
q.put(22)

print(q.full())  #判断对列是否已满,对列已满则返回True

# q.put(33,block=False)   #对列最多存放2个数据,第3个存不进去,默认情况是存不进去就一直阻塞等待,可以设置block=False:存不进去,就不等待直接报错
# q.put(33,timeout=2)    #数据存不进去也可以设置超时时间,过了超时时间之后还是没存进去就报错


print(q.qsize())    #查看对列中有多少个数据


#从队列中取出数据-----顺序:先进先出
print(q.get())
print(q.get())
# print(q.get(block=False))    #对列中已经没有数据可取,默认情况是阻塞等待,可以设置block=False:取不出数据就报错
# print(q.get(timeout=2))   #也可以设置超时时间,过了超时时间还没取到数据,就报错
'''


#join和task_done一般是一起使用的:
# 对列中的每个元素都被认为需要一个task来对其进行操作
# 对列中每个元素的task完成的标志是task完成后调用task_done,告诉对列该元素的task已经完成
# 当使用了join之后,表示需要对列中的每个元素的task都被完成后,程序才能结束,不然就一直阻塞

import queue

q = queue.Queue(2)

q.put(111)
q.put(222)

# print(q.get())
q.task_done()   #对列每取出一个数据,就执行一下tashk_done函数,告诉对列这个取出任务已经完成

# print(q.get())
q.task_done()

q.join()   #队列中还有数据,表示对列任务没有完成,就会一直阻塞,直到对列任务完成
            # 如果执行get获取了数据,但没有执行task_done,则认为任务没有完成,还是会一直阻塞
queue-1
#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
'''
除了一般对列,还有一些其他对列:
后进先出对列:后放进的数据先被取出

优先级对列:优先级高的数据先被取出

双向对列:对列两端都能进行存取
'''
import queue

#后进先出对列
q1 = queue.LifoQueue()
q1.put(123)
q1.put(456)
print(q1.get())


#优先级对列
q2 = queue.PriorityQueue()
q2.put((4,'eric'))
q2.put((0,'alex'))   #存数据的时候,放的是一个元组:第一个元素表示优先级(0优先级最高),第二个元素才是真正的数据
q2.put((0,'alex1'))   #优先级相同的情况下,哪个数据先存放,就先取哪个数据
q2.put((1,'maco'))
print(q2.get())


#双向对列
q3 = queue.deque()
q3.append(123)   #对列后面添加一条数据
q3.append(333)
q3.appendleft(456)  #对列左边添加一条数据

#上面添加数据完成后,顺序为456、123、333
print(q3.pop())  #从对列后面取出一个数据-----取出333-----对列变为:456、123
print(q3.popleft())  #从对列左边取出一个数据-----取出456----对列变为:123
queue-2

 

线程锁

#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
'''
多个线程同时对一个数据进行操作,可能会导致其结果错误,这时就需要用到线程锁

线程锁:同时只允许一个线程更改数据。----线程对共用的数据执行操作时,先对该数据上锁,
不让其他线程操作,等该线程操作完成后,再对数据进行解锁,这时其他线程才能对数据进行操作
'''
import threading
import time

NUM = 10

def func(lock):
    global NUM
    lock.acquire()   #要操作NUM,先对其进行上锁

    NUM -= 1
    time.sleep(1)
    print(NUM)

    lock.release()  #操作完成,解锁

#定义一把线程锁
# lock = threading.Lock()  #该类型的锁只支持一层锁,不支持锁中嵌套锁
lock = threading.RLock()  #另一种类型的锁,该类型的锁支持多层嵌套------通常使用该类型的锁

for i in range(10):
    t = threading.Thread(target=func,args=(lock,))
    t.start()
线程锁
#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
'''
线程锁:同一时刻只允许一个线程对数据进行更改
信号量:同一时刻允许一定数量的线程对数据进行更改-------信号量也是一种锁
事件(event):对所有进程要么全部阻塞,要么全部放行
'''

'''
#信号量
import threading
import time

NUM = 10

def func(lock,i):
    global NUM
    lock.acquire()   #要操作NUM,先对其进行上锁

    NUM -= 1
    time.sleep(1)
    print('NUM:%s 线程:%s'%(NUM,i))

    lock.release()  #操作完成,解锁

#定义一个信号量
lock = threading.Semaphore(5)   #同一时刻允许5个线程操作数据

for i in range(20):
    t = threading.Thread(target=func,args=(lock,i))
    t.start()
'''

#事件(event)机制:全局定义了一个Flag,如果Flag=False,则程序执行wait方法时就会阻塞,如果Flag=True,则wait方法就不再阻塞
#event设置Flag状态的方法:阻塞---event.clear()---Flag=False      不阻塞--event.set()---Flag=True
import threading

def func(event,i):
    print(i)
    event.wait()    #检测事件状态(是否进行阻塞)---默认为阻塞
    print(i+100)



if __name__ == '__main__':
    event = threading.Event()   #创建一个事件对象

    for i in range(10):
        t = threading.Thread(target=func,args=(event,i))
        t.start()

    event.clear()   #表示event.wait()处于阻塞状态
    inp = input('>>>')
    if inp == '1':
        event.set()   #表示event.wait()处于不阻塞状态
信号量和事件
#!/usr/bin/env python
# -*- coding: utf-8 -*-

'''
条件:使得线程等待,只有满足条件才放行n个进程

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

'''
#条件第一种使用方式
import threading

def func(con,n):
    #阻塞线程(acquire和wait是一起使用的)
    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=func,args=(con,i))
        t.start()

    while True:
        inp = input('>>>')
        if inp == 'q':  #输入q,退出进程
            break

        #下面是固定搭配
        con.acquire()
        con.notify(int(inp))   #参数为整数,参数是几,就放行几个进程
        con.release()
'''

'''
#条件第二种使用方式
import threading

def f():
    ret = False
    inp = input('>>>')
    if inp == 'true':
        ret = True
    else:
        ret = False
    return ret

def func(con,n):
    print(n)
    #阻塞线程(acquire和wait是一起使用的)
    con.acquire()
    con.wait_for(f)   #判断参数的真假(f的返回值),如果为True,则不再阻塞,否则继续阻塞,直到参数为True
    print(n+100)
    con.release()


if __name__ == '__main__':
    con = threading.Condition()   #创建一个条件对象

    for i in range(10):
        t = threading.Thread(target=func,args=(con,i))
        t.start()
'''

from threading import Timer

def hello():
    print('Hello World!')


t = Timer(5,hello)   #设置一个定时器,指定5秒后执行hello函数
t.start()
条件和定时器

 

线程池

#!/usr/bin/env python
# -*- coding: utf-8 -*-

'''
线程池:
需求:
线程池是一个容器,可设置最大个数-----对列
从线程池中获取线程,取一个少一个
线程池中没有线程了,就等待
任务执行完毕,交还线程
'''

import queue
import threading
import time


class ThreadPool:
    """
    自定义线程池
    """
    def __init__(self,maxsize=5):
        self.maxsize = maxsize   # 线程最大数
        self._q = queue.Queue(maxsize)   # 创建一个队列用来存放线程
        # 初始化线程池,存放最大线程数的threading.Thread类
        for i in range(maxsize):
            self._q.put(threading.Thread)

    def get_thread(self):
        """
        从线程池中取线程,线程池中没有线程了就等待
        :return:
        """
        return self._q.get()

    def add_thread(self):
        """
        任务执行完毕,交还线程,向线程池中添加新的threading.Thread类
        :return:
        """
        self._q.put(threading.Thread)


def task(args, p):
    print(args)
    time.sleep(1)

    p.add_thread()   #任务执行完毕,交还线程

if __name__ == '__main__':
    pool = ThreadPool(5)   # 创建一个线程池对象

    for i in range(100):
        t = pool.get_thread()   # 获取一个线程类
        obj = t(target=task, args=(i,pool))  # 创建一个线程对象
        obj.start()   # 启动线程
自定义线程池-1
#!/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:   # self.terminal为True,表示任务没有任务了
                    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):
    # import random
    # time.sleep(0.5)
    print(i)

for i in range(30):
    pool.run(action, (i,), callback)

while True:
    print(len(pool.generate_list), len(pool.free_list))

    if len(pool.free_list) == len(pool.generate_list):
        pool.close()
        print('END')
        break
    time.sleep(1)
# pool.terminate()
自定义线程池-2

 

posted on 2016-12-02 14:28  链条君  阅读(230)  评论(0编辑  收藏  举报