Python -- 多线程

--coding:utf-8--

2 python实现线程的方式

1.函数方式(涉及_thread模块)
2.用类包装线程对象(涉及threading模块)

2.1函数方式实现多线程

1.调用_thread模块的start_new_thread()函数创建并启动新线程
语法:_thread.start_new_thread(function,args[,kwargs])
function:线程函数
args:传递给线程函数的参数,必须是tuple类型
kwargs:可选参数
import _thread
import time
def workThread(threadName,delay):
    print('[启动]>>>{0}'.format(threadName))
    counter = 0 #计数器
    for i in range(delay):
        counter += 1
        time.sleep(1)
        pass
    print('[停止]>>>{0}'.format(threadName))
    pass

if __name__ == '__main__':
    _thread.start_new_thread(workThread,('thread-1',3))
    _thread.start_new_thread(workThread,('thread-2',5))
    for i in range(4):
        print('mainThread正在执行')
        time.sleep(1)
        pass
    print('>>>主线程mainThread停止\a')
    print('-' * 50)

备注:线程结束一般依靠线程函数的自然结束,也可在线程中调用thread.exit(),抛出SystemExit exception 达到退出线程的目的

2.2模块实现方式

python通过两个标准库_thread和threading提供线程支持
_thread提供低级别的,原始的线程以及一个简单的锁
threading模块提供其他方法:
1.threading.currentThread():返回当前线程变量
2.threading.enumerate():返回一个包含正在运行线程的list,正在运行线程启动后,结束前,不包括启动前和终止后的线程
3.threading.activeCount():返回正在运行的线程数量,与len(threading.enumerate())有相同的结果

除此之外,线程模块提供threading.Thread类来处理线程,threading.Thread提供如下函数
1.run():表示线程活动的方法
2.start():启动线程活动
3.join([time]):等待至线程中止,这阻塞调用线程直至线程的join()方法被调用中止-正常退出或者抛出未处理的异常-或者是可选
4.isAlive():返回线程是否是活动的
5.getName():返回线程名
6.setName():设置线程名

语法:
import threading
#创建线程类
class 线程类名称(threading.Thread):

    def __init__(self,参数1,...,参数N):
        #调用父类构造方法
        threading.thread.__init__(self)
        ...
    #重写run(),线程启动后的调用
    def run():
        ...

线程对象 = 线程类名称()
线程对象.run() #启动线程
import threading
import time
exitFlag = 0 #创建推出标志位变量

def outputTime(threadName,delay,counter):
    while counter:
        if exitFlag:
            threading.Thread.exit()
        time.sleep(delay)
        print('%s:%s' % (threadName,time.ctime(time.time())))
        counter -= 1
        pass
    pass

class MyThread(threading.Thread):
    """docstring for MyThread"""
    def __init__(self, threadID,name,counter):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.counter = counter
        
    def run(self):
        print('启动>' + self.name)
        outputTime(self.name,self.counter,5)
        print('结束>' + self.name)
        pass


if __name__ == '__main__':
    print('mainThread主线程启动.....')
    thread1 = MyThread(1,'thread-11',1)
    thread2 = MyThread(2,'thread-22',1)
    thread1.run()
    thread2.run()
    print('mainThread主线程结束')

3.线程同步

线程有五个状态,状态切换如下
      启动          调度          结束
新建          就绪          运行          死亡
                         | 阻塞条件
                        阻塞

所线程在执行时为随机模式,不可控,要求执行顺序可控就得用线程同步
Python 线程同步技术的解决方案:锁同步和条件变量同步

3.1创建线程锁的语法:
线程锁对象 = Threading.Lock
锁定:线程锁对象.acquire()
解除锁定:线程锁对象.release()

使用场景:
def run(self):
    线程锁对象.acquire()
    ...线程执行语句...
    线程锁对象.release()

#3.2条件变量同步
python 提供的Condition对象提供了对复杂线程同步问题的支持
Condition被称为条件变量,除了提供Lock类似的acquire和release方法,还提供wait和notify
工作原理:
线程首先acquire一个条件变量,然后判断一些条件,不满足wait,满足进行处理改变条件后,通过notify方法通知其他线程,其他处于wait的线程接到通知会重新判断条件,重复这一过程,从而解决复杂的同步问题

示例:生产者和消费者

生产者消费者问题(有限缓冲问题),是一个多线程同步的经典案例,该问题描述两个共享固定大小缓存的线程--即所谓的‘生产者‘和’消费者‘在实际运行时会发生的问题
生产者作用时生成一定量的数据放到缓冲区,重复此过程
消费者在缓冲区消耗这些数据
该问题的【关键】保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区空时消耗数据
任务说明:
1.创建一个共享区,容量是10
2.两个生产者,随机时间单位产生1件商品放入共享区,count + 1,共享区满,生产者停止放入共享区,线程进入block阻塞状态,等待消费者线程唤醒
3.五个消费者,随机时间单位产生从共享区取1件商品,count - 1,共享区空,消费者停止从共享区获取,线程进入block阻塞状态,等待生产者线程唤醒

import threading
import time
import random #随机模块
#使用共享区模拟变量
count= 0 
#创建条件对象
condition = threading.Condition()

#生产者线程类
class Producer(threading.Thread):
    def __init__(self,threadName):
        threading.Thread.__init__(self)
        self.threadName = threadName

    def run(self):
        global count #引用全局共享变量count
        while True:
            #使用条件变量后去锁并速定
            if condition.acquire():
                #判断共享变量是否达到上限(已满)
                if count >= 10:
                    print('共享区已满,生产者Producer线程进入阻塞block状态,停止放入!')
                    #当前线程进入阻塞状态
                    condition.wait()
                else:
                    count += 1 #共享变量自增1
                    print(time.ctime() + ' ' + self.threadName + '生产了1件商品放入共享区,共享区商品总计个数:{0}'.format(count))
                    condition.notify() #唤醒其他阻塞线程
                condition.release()
                time.sleep(random.randrange(10)/5) #随机休眠N秒


#消费者线程
class Customer(threading.Thread):
    def __init__(self, threadName):
        threading.Thread.__init__(self)
        self.threadName = threadName

    def run(self):
        global count #引用全局共享变量count
        while True:
            #使用条件变量后去锁并速定
            if condition.acquire():
                #判断共享变量是否达到上限(已满)
                if count < 1:
                    print('共享区已空,消费者Customer线程进入阻塞block状态,停止获取!')
                    #当前线程进入阻塞状态
                    condition.wait()
                else:
                    count -= 1 #共享变量自减1
                    print(time.ctime() + ' ' + self.threadName + '消费了1件商品,共享区商品总计个数:' + str(count))
                    condition.notify() #唤醒其他阻塞线程
                condition.release()
                time.sleep(random.randrange(10)) #随机休眠N秒

if __name__ == '__main__':
    for i in range(2):
        p = Producer('[生产者-' + str(i + 1) + ']')
        p.start()

    for i in range(5):
        c = Producer('[消费者-' + str(i + 1) + ']')
        c.start()

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 一文读懂Python多线程 1、线程和进程 计算机的核心是CPU,它承担了所有的计算任务。它就像一座工厂,时刻在运...
    星丶雲阅读 1,480评论 0 4
  • Python 多线程 多线程类似于同时执行多个不同程序,多线程运行有如下优点: 使用线程可以把占据长时间的程序...
    今早上阅读 356评论 0 0
  • 免费Python课程:阿里云大学——开发者课堂 Python中使用线程有两种方式:函数或者用类来包装线程对象。 函...
    开发者学习指南阅读 208评论 0 0
  • 多线程基础概念 并行与并发 并行:同时处理多个任务,必须在多核环境下 一段时间内同时处理多个任务,单核也可以并发 ...
    职场亮哥阅读 666评论 0 0
  • 久违的晴天,家长会。 家长大会开好到教室时,离放学已经没多少时间了。班主任说已经安排了三个家长分享经验。 放学铃声...
    飘雪儿5阅读 7,557评论 16 22