美文网首页并发编程
Python的并发编程(二)-多线程的执行状态

Python的并发编程(二)-多线程的执行状态

作者: SavingUnhappy | 来源:发表于2019-05-09 17:21 被阅读0次

上一篇文章我们写了一个简单的多线程,我们使用start()来启动这个线程,但是如果我们想知道它实际会在什么时候开始运行呢?

获取线程状态

使用Event同步线程状态

线程的核心特点就是它们能够以非确定性的方式独立执行。即,什么时候开始执行、何时被打断、何时恢复执行等状态完全由操作系统来调度管理,这是用户和程序员都无法确定的。如果程序中有其他线程需要判断某个线程是否执行到了某个点,根据这个来判断后续的操作,那就产生了线程同步的问题。

要解决这类问题,我们可以使用threading中的Event对象。

import time

from threading import Thread, Event

def countdown(n, started_evt):
    print("开始")
    started_evt.set()
    while n > 0:
        print("n=", n)
        n-=1
        time.sleep(5)

# 创建一个Event对象
started_evt = Event()

print("启动 countdown")

t = Thread(target=countdown, args=(10, started_evt))
t.start()

# 等待线程开始

started_evt.wait()
print("countdown 正在执行")

Event对象和条件标记(sticky flag)类似,允许县城等待某个事件发生。初始状态时事件被设置为0。如果时间没有被设置而线程正在等待该事件,那么线程就会被阻塞(休眠状态),直到事件被设置为止。当有线程设置了这个事件时,这回唤醒所有正在等待该事件的线程(如果存在)。如果线程等待的事件已经设置了,那么线程会继续执行。

上面的代码执行结果如下:

启动 countdown
开始
n= 10
countdown 正在执行
n= 9
n= 8
n= 7
n= 6
n= 5
n= 4
n= 3
n= 2
n= 1

“countdown 正在执行”总是会在“启动 countdown”之后打印,这里使用了时间来同步线程,使主线程等待。

代码执行的顺序为:

  1. t.start() 启动线程。
  2. 顺序执行到started_evt.wait()的时候,会等待started_evt.set()的执行。

如果注释了started_evt.set()就会在started_evt.wait()处阻塞,“countdown 正在执行”也不会被打印,可以自己多修改代码调试,观察打印情况。

使用Condition通知事件代替Event

Event对象最好之用于一次性的事件,也就是说,我们创建一个事件,让线程等待时间被设置,然后一旦完成了设置,Event对象就被丢弃。尽管可以使用Event对象的clean()方法来清除事件,但是要安全地清楚事件并等待它被再次设置这个过程很难同步协调,可能会在成事件丢失,死锁或者其他问题(特别是,在设置完事件之后,我们无法保证发起的时间清除请求就一定会在线程再次等待该事件之前被执行)。

比如上面的代码:

started_evt.clear()
print("tag")
started_evt.wait()
print("countdown 正在执行11")

在后面填家上面的代码,每次运行结果中,tag的打印位置是不确定的。

如果线程打算一遍又一遍地重复通知某个事件,那最好使用Condition对象来处理。

下面的代码实现了一个周期性的定时器,每当定时器超时,其他的线程都可感知到超时事件。


import time

from threading import Thread, Condition

class PeriodicTimer:
    def __init__(self, interval):
        self._interval = interval
        self._flag = 0
        self._cv = Condition()

    def start(self):
        t = Thread(target=self.run)
        t.daemon = True
        t.start()

    def run(self):
        while True:
            time.sleep(self._interval)
            with self._cv:
                self._flag ^= 1
                self._cv.notify_all()

    def wait_for_tick(self):
        while self._cv:
            last_flag = self._flag
            while last_flag == self._flag:
                self._cv.wait()

ptimer = PeriodicTimer(5)
ptimer.start()

def countdown(nticks):
    while nticks > 0:
        ptimer.wait_for_tick()
        print("n=", nticks)
        nticks -= 1

def countup(last):
    n = 0
    while n < last:
        ptimer.wait_for_tick()
        print("n=", n)
        n += 1

Thread(target=countdown, args=(10, )).start()
Thread(target=countup, args=(5, )).start()

Event 对象的关键特性就是他会唤醒所有等待的线程。如果我们编写的程序只希望唤醒一个单独的等待线程,那么最好使用Semaphore或者Condition对象。

本文最先发布于:SavingUnhappy

相关文章

  • Python的并发编程(二)-多线程的执行状态

    上一篇文章我们写了一个简单的多线程,我们使用start()来启动这个线程,但是如果我们想知道它实际会在什么时候开始...

  • Java并发编程知识点梳理

    一 并发编程基础知识 1.1 概念 并发编程是你编写的代码有可能在多线程环境中执行, 1.2 为什么要用并发编程...

  • python并发编程:多线程

    并发编程之多线程 python中的并发编程,一个是协程,另一个就是多线程了。它们都用于IO操作频繁的场景。 基于T...

  • Python 并发编程简介

    1 多线程和多进程 Python语言中既有多线程编程也有多进程编程,也叫做并发编程。 多进程 把一个程序分成几个不...

  • 5-线程(补充)

    Python多线程原理与实战 目的: (1)了解python线程执行原理 (2)掌握多线程编程与线程同步 (3)了...

  • 多线程

    Python多线程原理与实战 目的: (1)了解python线程执行原理 (2)掌握多线程编程与线程同步 (3)了...

  • python3 多线程编程实战: http多线程下载器的编写

    python3 多线程编程实战: http多线程下载器的编写说到多线程的应用,这种并发下载的情况显然比较适合。也是...

  • iOS多线程与线程同步技术

    为什么要学习多线程编程? 多线程编程能够更加充分合理的利用操作系统多核cpu,能让多核cpu并发执行多个任务,比如...

  • Spring Boot 多线程

    Spring通过任务执行器TaskExecutor,来实现多线程和并发编程,使用ThreadPoolTaskExe...

  • Spring多线程

    Spring通过任务执行器(TaskExecutor)来实现多线程和并发编程。使用TreadPoolTaskExe...

网友评论

    本文标题:Python的并发编程(二)-多线程的执行状态

    本文链接:https://www.haomeiwen.com/subject/fylgoqtx.html