python3-多线程

来源:互联网 发布:sql查询成绩最高分 编辑:程序博客网 时间:2024/05/20 13:37

Python多线程

基本概念

多线程类似于同时执行多个不同程序,多线程运行有如下优点:

  • 使用线程可以把占据长时间的程序中的任务放到后台去处理。
  • 用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度程序的运行速度可能加快
  • 在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了。在这种情况下我们可以释放一些珍贵的资源如内存占用等等。
线程和进程:

线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中由应用程序提供多个线程执行控制。

每个线程都有他自己的一组CPU寄存器,称为线程的上下文,该上下文反映了线程上次运行该线程的CPU寄存器的状态。

指令指针和堆栈指针寄存器是线程上下文中两个最重要的寄存器,线程总是在进程得到上下文中运行的,这些地址都用于标志拥有线程的进程地址空间中的内存。

线程可以被抢占(中断)。

在其他线程正在运行时,线程可以暂时搁置(也称为睡眠) -- 这就是线程的退让。

线程可以分为:

  • 内核线程:由操作系统内核创建和撤销。
  • 用户线程:不需要内核支持而在用户程序中实现的线程。


多线程优缺点
        优点
            (1)能适当提高程序的执行效率。
            (2)能适当提高资源利用率(CPU、内存利用率)
        缺点
            (1)开启线程需要占用一定的内存空间(默认情况下,主线程占用1M,子线程占用512KB),如果开启大量的线程,会占用大量的内存空间,降低程序的性能。
            (2)线程越多,CPU在调度线程上的开销就越大。
            (3)程序设计更加复杂:比如线程之间的通信、多线程的数据共享

Python3 线程中常用的两个模块为:

  • _thread
  • threading(推荐使用)

thread 模块已被废弃。用户可以使用 threading 模块代替。所以,在 Python3 中不能再使用"thread" 模块。为了兼容性,Python3 将 thread 重命名为 "_thread"。



threading 模块除了包含 _thread 模块中的所有方法外,还提供的其他方法:

  • run(): 用以表示线程活动的方法。
  • start():启动线程活动。

  • join([time]): 等待至线程中止。这阻塞调用线程直至线程的join() 方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生。
  • isAlive(): 返回线程是否活动的。
  • getName(): 返回线程名。
  • setName(): 设置线程名。

详细示例:

以下是一些示例:

class Mythread(threading.Thread):    def __init__(self):        threading.Thread.__init__(self)        print("Mythread")    def run(self):        for i in range(1,11):             print(i)             time.sleep(1)    def start(self):        print("开始Mythread")        threading.Thread.start(self)print("mian....")t=Mythread()t.start()t.join()#阻断当前线程,当加入的线程执行完成后,当前线程才能继续

运行结果先输出1-10,最后在输出main....所以说join的作用也体现出来了,谁调用谁阻塞,main..作为主线程调用了join所以等到线程t运行完了以后,才会执行

继续看一下下一个比较典型的示例:

import threadingimport timeclass Thread1(threading.Thread):    def run(self):        for i in range(1,11):            if i == 3:                condition.acquire()                condition.wait()                condition.release()            print(i)            time.sleep(1)class Thread2(threading.Thread):    def run(self):        for i in range(30,19,-1):            if i == 25:                condition.acquire()                condition.notify()                condition.release()            print(i)            time.sleep(1)lock=threading.Lock()condition=threading.Condition(lock=lock)Thread1().start()Thread2().start()


wait:让线程陷入休眠状态
notify:让当前休眠的线程继续工作
但是在使用这一类的方法之前需要有condition中的两个方法的支持
分别是condition.acquire()和condition.release()
这两个方法其实是线程锁下面简短的解释:

对于多线程来说,最大的特点就是线程之间可以共享数据,那么共享数据就会出现多线程同时更改一个变量,使用同样的资源,而出现死锁、数据错乱等情况。假设有两个全局资源,a和b,有两个线程thread1,thread2. thread1占用a,想访问b,但此时thread2占用b,想访问a,两个线程都不释放此时拥有的资源,那么就会造成死锁。对于该问题,出现了Lock。 当访问某个资源之前,用Lock.acquire()锁住资源,访问之后,用Lock.release()释放资源。

以下是一个在线程中很经典的一个和尚吃馒头的例子:

需求:四个和尚,一个做馒头的三个吃馒头的,做馒头的需要先做10个馒头然后叫醒三个吃馒头的,之后自己进入休眠
三个和尚一个一个去拿馒头,只要有一个和尚发现没馒头了,就去叫醒做馒头的,之后三个吃馒头的去进行休眠
就这样一直循环。
        
class zhengThread(threading.Thread):    def __init__(self,name=None):        threading.Thread.__init__(self);        self.name=name    def run(self):        while True:            condition.acquire()            if len(guo) == 0:                for i in range(1,11):                    guo.append(i)                    print("做出第{0}个馒头".format(i))                    time.sleep(1)                condition.notify_all()            condition.release()            condition2.acquire()            condition2.wait()            condition2.release()class chiThread(threading.Thread):    def __init__(self,name=None):        threading.Thread.__init__(self);        self.name=name    def run(self):        while True:            mantou=None            condition.acquire()            if len(guo) == 0:                condition2.acquire()                condition2.notify()                condition2.release()                condition.wait()            else:                mantou=guo.pop()            condition.release()            if mantou is not None:                print("{0}正在开始吃第{1}个馒头".format(self.name,mantou))                time.sleep(random.choice([1,2,3,4,5]))import randomguo=[]lock=threading.Lock()condition=threading.Condition(lock=lock)    #吃的锁lock2=threading.Lock()condition2=threading.Condition(lock=lock2)  #蒸的锁zhengThread(name="大头和尚").start()chiThread(name="白眉和尚").start()chiThread(name="花和尚").start()chiThread(name="牛鼻子和尚").start()