多线程

Python通过两个标准库_thread 和threading提供对线程的支持 , threading对_thread进行了封装。threading模块中提供了Thread , Lock , RLock , Condition等组件。 

因此在实际的使用中我们一般都是使用threading

1 线程的实现:


在python中有两种方法实现创建线程,实例Thread类和继承重写Thread类

实例Thread类

from threading import Thread,Lock

import time

def a(name):

    print('好好学习%s'%name)

    time.sleep(3)

    print('天天向上')

def b(name):

    print('你好%s'%name)

    time.sleep(3)

    print('世界')

# a()

# b()

#创建子线程

a_thread= Thread(target=a,args=('王磊',),name='wl')

b_thread= Thread(target=b,args=('彤颖',),name='ty')    #args是一个元祖,必须加逗号 args参数传给target调用对象 name是子线程的名称

#获取子线程的名称

print(a_thread.getName())

print(b_thread.getName())

#给子线程添加守护线程(主线程执行完,子线程也就完了)

a_thread.setDaemon(True)

b_thread.setDaemon(True)

#开启子线程

a_thread.start()            #start方法启动run方法,run方法又调用子线程target参数(函数) 

b_thread.start()

#子线程阻塞(等到子线程执行完才执行主线程)

a_thread.join()

b_thread.join()

print('主线程执行完了')


继承Thread类

join和setDaemon区别:

在说这两个方法之前,我们需要了解主线程和子线程的概念

主线程 : 当一个程序启动时 , 就有一个线程开始运行 , 该线程通常叫做程序的主线程

子线程 : 因为程序是开始时就执行的 , 如果你需要再创建线程 , 那么创建的线程就是这个主线程的子线程

主线程的重要性体现在两方面 :

1. 是产生其他子线程的线程

2. 通常它必须最后完成执行比如执行各种关闭操作

join:阻塞调用程序,直到调用join方法的线程执行完,才继续往下执行

setDaemon:join会等子线程执行完才往下执行,setDaemon不会等,主线程执行完,子线程跟着结束


线程间的通信:

互斥锁:在多线程中 , 所有变量对于所有线程都是共享的 , 因此 , 线程之间共享数据最大的危险在于多个线程同时修改一个变量 , 那就乱套了 , 所以我们需要互斥锁 , 来锁住数据。

from threading import Thread,Lock

lock= Lock()  #线程锁

x= 0

n= 10000000

def a(n):

    global x

    for i in range(n):

        lock.acquire()    #加锁

        x+= 1

        lock.release()    #解锁

def b(n):

    global x

    for i in range(n):

        lock.acquire()

        x-= 1

        lock.release()

#创建子线程

a_thread= Thread(target=a,args=(n,))

b_thread= Thread(target=b,args=(n,))

a_thread.start()      #开启线程

b_thread.start()

a_thread.join()    #要等子线程执行完才能往下执行

b_thread.join()

print(x) 


#队列:先进先出

入队:put()   出对:get()   测试空:empty()  测试满: full()    队列长度:qsize()   任务结束:task_done()    等待完成:join()

#队列

from queue import Queue

q= Queue(5)

q.put(1)

q.put(2)

q.put(3)

q.put(4)

q.put(5)

print(q.get())

print(q.get())

print(q.get())

print(q.get())

print(q.get())

print(q.empty())     #队列是否空

print(q.full())          #队列是否满

print(q.qsize())      #队列中的剩余长度

q.task_done()      

q.task_done()

q.task_done()

q.task_done()                #没get取出一次,就结束一次

q.task_done()

q.join()         #队列执行完了才能往下执行,怎么看执没执行完,看task_done调用次数,

print('主线程执行完了')


线程池:

主线程: 相当于生产者,只管向线程池提交任务。   并不关心线程池是如何执行任务的。因此,并不关心是哪一个线程执行的这个任务。

线程池: 相当于消费者,负责接收任务,并将任务分配到一个空闲的线程中去执行。


##自己手写实现线程池:

from threading import Thread

from queue import Queue

import time

class MyThreadPool:

    def __init__(self,n):

        self.queue= Queue()  #开启列队

        for i in range(n):       #开启多个子线程

            Thread(target=self.worker,daemon=True).start()     #线程池默认自己开启,并且子线程是守护线程

    def worker(self):

        while True:

            func,args,kwargs= self.queue.get()

            func(*args,**kwargs)

            self.queue.task_done()

    def apply_async(self,func,args=(),kwds={}):

        self.queue.put((func,args,kwds))

    def join(self):                     

        self.queue.join()

def task(name):

    time.sleep(2)

    print('%s好好学习'%name)

pool= MyThreadPool(5)                      #创建实例     5个子线程

for i in range(10):                                #一个函数执行10次,就是10个任务

    pool.apply_async(task,(i,))

pool.join()                                            #线程阻塞,等待子线程执行完了,再能往下执行

print('主线程执行完了')


##python内置线程池

from multiprocessing.pool import ThreadPool

import time

def task1(name):

    time.sleep(2)

    print('%s好好学习'%name)

def task2(*args,**kwargs):

    time.sleep(2)

    print('天天向上',args,kwargs)

def  task3():

    time.sleep(2)

    print('你好')

def task4():

    time.sleep(2)

    print('世界')

pool= ThreadPool(4)                                 #线程池设有四个子线程

pool.apply_async(task1,('王磊',))

pool.apply_async(task2,(1,2,3),{'a':1,'b':2})

pool.apply_async(task3)

pool.apply_async(task4)

pool.close()      #线程池关闭  就不能再提交任务了

pool.join()      #线程池中的子线程默认开启,并且是守护线程,所以要阻塞(子线程执行完了才能往下执行)

print('主线程执行完了')

你可能感兴趣的:(多线程)