一、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条执行之后,当多个线程同时修改同一条数据时可能会出现脏数据,所以,出现了线程锁 - 同一时刻允许一个线程执行操作。




python 提交任务给线程池 python创建线程池_python 提交任务给线程池

python 提交任务给线程池 python创建线程池_线程池_02

#!/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是最简单的线程间通信的方式




python 提交任务给线程池 python创建线程池_python 提交任务给线程池

python 提交任务给线程池 python创建线程池_线程池_02

一、多线程同步
由于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()




python 提交任务给线程池 python创建线程池_python 提交任务给线程池

python 提交任务给线程池 python创建线程池_线程池_02

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')




python 提交任务给线程池 python创建线程池_python 提交任务给线程池

python 提交任务给线程池 python创建线程池_线程池_02

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()


线程池