返回顶部
首页 > 资讯 > 后端开发 > Python >Threading in Python-
  • 557
分享到

Threading in Python-

ThreadingPython 2023-01-31 02:01:54 557人浏览 安东尼

Python 官方文档:入门教程 => 点击学习

摘要

原文是2.x版本的,然后应该是英文的.我在学习的过程中,同时改成python 3.3并且改成中文,引入一些自己的理解.Thread Objects线程对象The simplest way to use a Thread is to inst

原文是2.x版本的,然后应该是英文的.我在学习的过程中,同时改成python 3.3并且改成中文,引入一些自己的理解.

Thread Objects

线程对象


The simplest way to use a Thread is to instantiate it with a target function and call start() to let it begin working

最简单的线程应用就是初始化一个目标函数,调用start()函数,运行之~.

import threading
def worker():
    """thread worker function"""
    print ('Worker')
    return
threads = []
for i in range(5):
    t = threading.Thread(target=worker)
    threads.append(t)
    t.start()

运行结果

>>>
WorkerWorkerWorkerWorkerWorker

这里遇到奇怪的状况,没有分行打印.


It useful to be able to spawn a thread and pass it arguments to tell it what work to do. This example passes a number, which the thread then prints.

然后呢,这个目标函数,是可以带参数的。例子里面传递了一个数字从拿书,然后在线程里面打印它

import threading
def worker(num):
    """thread worker function"""
    print ('Worker:%s'%num)
    return
threads = []
for i in range(5):
    t = threading.Thread(target=worker,args=(i,))
    #print(type(t.getName))
    #print(type(t.name))
    threads.append(t)
    t.start()

运行结果

>>>
Worker:0Worker:2Worker:1Worker:3Worker:4

还是没有分行。很奇怪




Determining the Current Thread

确定当前进程


Using arguments to identify or name the thread is cumbersome, and unnecessary. Each Thread instance has a name with a default value that can be changed as the thread is created. Naming threads is useful in server processes with multiple service threads handling different operations.

用参数来定义或者命名一个线程太笨拙,也没什么意义。每个线程在创建伊始就已经被指定了一个默认的可变的值。在sever需要用不同的线程服务处理不同的操作的时候,对线程进行命名还是有意义的。

import time
import threading
def worker():
    print (threading.currentThread().getName()+'Starting\n')
    time.sleep(2)
    print (threading.currentThread().getName()+ 'Exiting\n')
def my_service():
    print (threading.currentThread().getName()+ 'Starting\n')
    time.sleep(3)
    print (threading.currentThread().getName()+ 'Exiting\n')
t = threading.Thread(name='my_service', target=my_service)
w = threading.Thread(name='worker', target=worker)
w2 = threading.Thread(target=worker) # use default name
w.start()
w2.start()
t.start()

为了运行结果清晰一点,没办法,额外加了换行符。

The debug output includes the name of the current thread on each line.

The lines with "Thread-1" in the thread name column correspond to the unnamed thread w2.

debug输出的内容包括每一行的当前线程名和线程状态

“Thread-1”是未命名的默认线程名。这个w2不知道是指什么

>>>
workerStarting
Thread-1Starting
my_serviceStarting
>>>
workerExiting
Thread-1Exiting
my_serviceExiting


Most programs do not use print to debug. The logging module supports embedding the thread name in every log message using the fORMatter code %(threadName)s.

Including thread names in log messages makes it easier to trace those messages back to their source.

多数的时候,我们不用print来做debug。logging模块支持利用格式化编码符号%(threadName)s把线程名之类的信息嵌入到每一个message里。

把线程名什么的嵌入到log中可以让我们更加容易追踪源头

import logging
import threading
import time
logging.basicConfig(level=logging.DEBUG,
                    format='[%(levelname)s] (%(threadName)-10s) %(message)s',
                    )
def worker():
    logging.debug('Starting')
    time.sleep(2)
    logging.debug('Exiting')
def my_service():
    logging.debug('Starting')
    time.sleep(3)
    logging.debug('Exiting')
t = threading.Thread(name='my_service', target=my_service)
w = threading.Thread(name='worker', target=worker)
w2 = threading.Thread(target=worker) # use default name
w.start()
w2.start()
t.start()

logging is also thread-safe, so messages from different threads are kept distinct in the output.

logging是 thread-safe的。不同线程间的message可以在output里面清晰的看出来。

>>>
[DEBUG] (worker    ) Starting
[DEBUG] (Thread-1  ) Starting
[DEBUG] (my_service) Starting
[DEBUG] (worker    ) Exiting
[DEBUG] (Thread-1  ) Exiting
[DEBUG] (my_service) Exiting




Daemon vs. Non-Daemon Threads

守护线程 vs 非守护线程


Up to this point, the example programs have implicitly waited to exit until all threads have completed their work. Sometimes programs spawn a thread as a daemon that runs without blocking the main program from exiting. Using daemon threads is useful for services where there may not be an easy way to interrupt the thread or where letting the thread die in the middle of its work does not lose or corrupt data (for example, a thread that generates “heart beats” for a service monitoring tool). To mark a thread as a daemon, call its setDaemon() method with a boolean argument. The default is for threads to not be daemons, so passing True turns the daemon mode on.

这个例程,默默的等待所有的线程完成工作。有的时候程序生成一个守护线程,它运行并不阻塞主程序(我理解就是主程序退出了,他可以继续执行)。使用守护进程对于服务来说是很有用的。因为一个进程不会轻易被中断,同时,中断一个运行中的进程也不会丢失数据或让数据崩溃(比如中断一个产生“心跳”来监听服务的进程)。调用一个布尔型函数setDaemon()来把一个线程标记为守护线程。默认状态下,线程是非守护线程,赋值传参True把一个线程改成守护线程模式。


import threading
import time
import logging
logging.basicConfig(level=logging.DEBUG,
                    format='(%(threadName)-10s) %(message)s',
                    )
def daemon():
    logging.debug('Starting')
    time.sleep(2)
    logging.debug('Exiting')
d = threading.Thread(name='daemon', target=daemon)
d.setDaemon(True)
def non_daemon():
    logging.debug('Starting')
    logging.debug('Exiting')
t = threading.Thread(name='non-daemon', target=non_daemon)
d.start()
t.start()

我的运行结果是:

>>> (daemon    ) Starting
(non-daemon) Starting
(non-daemon) Exiting
(daemon    ) Exiting

原作者文章中的运行结果是:

$ Python threading_daemon.py

(daemon    ) Starting
(non-daemon) Starting
(non-daemon) Exiting

原文中这样说:

Notice that the output does not include the "Exiting" message from the daemon thread, since all of the non-daemon threads (including the main thread) exit before the daemon thread wakes up from its two second sleep.“”可以看到,daemon 线程的输出中不包括“Exiting“这条信息。因为所有的非守护线程(包括主线程)都已经能够在daemon线程睡眠的2秒醒来前结束。

不知道是不是python3.3有什么变化,以后看到在修改。


To wait until a daemon thread has completed its work, use the join() method.

要等到守护进程完成工作,用 join() 方法

import threading
import time
import logging
logging.basicConfig(level=logging.DEBUG,
                    format='(%(threadName)-10s) %(message)s',
                    )
def daemon():
    logging.debug('Starting')
    time.sleep(2)
    logging.debug('Exiting')
d = threading.Thread(name='daemon', target=daemon)
d.setDaemon(True)
def non_daemon():
    logging.debug('Starting')
    logging.debug('Exiting')
t = threading.Thread(name='non-daemon', target=non_daemon)
d.start()
t.start()
d.join()
t.join()

Waiting for the daemon thread to exit using join() means it has a chance to produce its "Exiting" message.

等着守护线程完成工作后退出用join(),也就是这里的守护线程有机会输出”Exiting“这条message

>>>
(daemon    ) Starting
(non-daemon) Starting
(non-daemon) Exiting
(daemon    ) Exiting


By default, join() blocks indefinitely. It is also possible to pass a timeout argument (a float representing the number of seconds to wait for the thread to become inactive). If the thread does not complete within the timeout period, join() returns anyway.、

默认状态下,join()会无限期(还是不定期)的阻塞。它有可能会引发超时(一个浮点数代表,可以等待这个线程继续工作的等待时间)。如果线程没在超时限期内完成,join( )了也会结束。

import threading
import time
import logging
logging.basicConfig(level=logging.DEBUG,
                    format='(%(threadName)-10s) %(message)s',
                    )
def daemon():
    logging.debug('Starting')
    time.sleep(2)
    logging.debug('Exiting')
d = threading.Thread(name='daemon', target=daemon)
d.setDaemon(True)
def non_daemon():
    logging.debug('Starting')
    logging.debug('Exiting')
t = threading.Thread(name='non-daemon', target=non_daemon)
d.start()
t.start()
d.join(1)
print ('d.isAlive()'+str(d.isAlive()))
t.join()

Since the timeout passed is less than the amount of time the daemon thread sleeps, the thread is still “alive” after join() returns.

因为时限设定了1秒小于守护进程sleep的2秒,所以这个线程在join()结束后仍然alive。

我自己实验了d.join(3),结果d.isAlive()就是false了,因为已经返回了。



Enumerating All Threads

枚举所有线程


It is not necessary to retain an explicit handle to all of the daemon threads in order to ensure they have completed before exiting the main process. enumerate()returns a list of active Thread instances. The list includes the current thread, and since joining the current thread is not allowed (it introduces a deadlock situation), it must be skipped.

没必要保持一个明确的handle来确保所有守护线程在主进程完成之前结束。enumerate()返回一个现存的线程列表。列表中包含现存线程,而调用列表函数的线程是不能和现存线程join的(否则就会包含死),所以本身这个线程就要被忽略。(后半句翻译是猜测的,,感觉只有这样说的通,回头看看在修改)

import random
import threading
import time
import logging
logging.basicConfig(level=logging.DEBUG,
                    format='(%(threadName)-10s) %(message)s',
                    )
def worker():
    """thread worker function"""
    t = threading.currentThread()
    pause = random.randint(1,5)
    logging.debug('sleeping %s', pause)
    time.sleep(pause)
    logging.debug('ending')
    return
for i in range(3):
    t = threading.Thread(target=worker)
    t.setDaemon(True)
    t.start()
main_thread = threading.currentThread()
for t in threading.enumerate():
    if t is main_thread:
        continue
    logging.debug('joining %s', t.getName())
    t.join()

Since the worker is sleeping for a random amount of time, the output from this program may vary. It should look something like this

原文作者说,sleep时间是随机的,所以结果可能不同,原文的结果如下

$ python threading_enumerate.py
(Thread-1  ) sleeping 3
(Thread-2  ) sleeping 2
(Thread-3  ) sleeping 5
(MainThread) joining Thread-1
(Thread-2  ) ending
(Thread-1  ) ending
(MainThread) joining Thread-3
(Thread-3  ) ending
(MainThread) joining Thread-2

但是我运行后结果是这样的

(Thread-1  ) sleeping 2
(Thread-2  ) sleeping 3
(Thread-3  ) sleeping 3
(MainThread) joining Thread-1
(Thread-1  ) ending
(MainThread) joining SockThread
(Thread-2  ) ending
(Thread-3  ) ending

刚开始的时候 只有joining SockThread,后来意外的出现了Thread-1.分析、查找、咨询大神们总结了一下原因,应该是用threading.enumerate()出现了问题。因为他是全局线程的列表。据说所有的线程都出现在这个列表里,经测,出现了一个叫SockThread的线程,它从哪里来的呢?猜测会不会是因为用IDLE运行的结果呢?

然后不用IDLE直接运行,结果如作者的结果所示。个人猜测这个SockThread是IDLE对应的一个线程。

这里总结经验,慎用threading.enumerate()。如需要用到线程列表,还是自己保下来的好。




Subclassing Thread

At startup,a Thread does some basic initialization and then calls its run() method, which calls the target function passed to the constructor. To create a subclass ofThread, override run() to do whatever is necessary.

开始阶段,一个线程会做一些基本的初始化操作,然后调用它的run()函数,这个函数会把目标函数传递给constructor。想要创建一个Thread的子集,可以随意重写run()函数

import threading
import logging
logging.basicConfig(level=logging.DEBUG,
                    format='(%(threadName)-10s) %(message)s',
                    )
class MyThread(threading.Thread):
    def run(self):
        logging.debug('running')
        return
for i in range(5):
    t = MyThread()
    t.start()

The return value of run() is ignored.

run()函数的返回值被忽略掉

(Thread-1  ) running
(Thread-2  ) running
(Thread-3  ) running
(Thread-4  ) running
(Thread-5  ) running


Because the args and kwargs values passed to the Thread constructor are saved in private variables, they are not easily accessed from a subclass. To pass arguments to a custom thread type, redefine the constructor to save the values in an instance attribute that can be seen in the subclass.

因为args和kwargs参数在Thread构造的时候被保存为私有成员变量,子类不容易访问他们。为了传递参数,在样例程序中重定义构造函数让它们在子类中变成可见的!

import threading
import logging
logging.basicConfig(level=logging.DEBUG,
                    format='(%(threadName)-10s) %(message)s',
                    )
class MyThreadWithArgs(threading.Thread):
    def __init__(self, group=None, target=None, name=None,
                 args=(), kwargs=None):
        threading.Thread.__init__(self, group=group, target=target, name=name)
        self.args = args
        self.kwargs = kwargs
        return
    def run(self):
        logging.debug('running with %s and %s', self.args, self.kwargs)
        return
for i in range(5):
    t = MyThreadWithArgs(args=(i,), kwargs={'a':i, 'b':'B'})
    t.start()

MyThreadWithArgs uses the same api as Thread, but another class could easily change the constructor method to take more or different arguments more directly related to the purpose of the thread, as with any other class.

MyThreadWithArgs 用和Thread 相同的API,但是可以轻松的改变构造函数,来完成更多或者不同的功能,来满足用户需求。(ps:args是无名参数,kwargs是有名的参数,args应该在kwargs前)

(Thread-1  ) running with (0,) and {'a': 0, 'b': 'B'}
(Thread-2  ) running with (1,) and {'a': 1, 'b': 'B'}
(Thread-3  ) running with (2,) and {'a': 2, 'b': 'B'}
(Thread-4  ) running with (3,) and {'a': 3, 'b': 'B'}
(Thread-5  ) running with (4,) and {'a': 4, 'b': 'B'}


Timer Threads

One example of a reason to subclass Thread is provided by Timer, also included in threading. A Timer starts its work after a delay, and can be canceled at any point within that delay time period.

Thread的一个重要继承类是Timer,它也在threading目录下。一个Timer对象在一个delay后开始工作,并且可以在工作时间的任意时刻被中止掉。

import threading
import time
import logging
logging.basicConfig(level=logging.DEBUG,
                    format='(%(threadName)-10s) %(message)s',
                    )
def delayed():
    logging.debug('worker running')
    return
t1 = threading.Timer(3, delayed)
t1.setName('t1')
t2 = threading.Timer(3, delayed)
t2.setName('t2')
logging.debug('starting timers')
t1.start()
t2.start()
logging.debug('waiting before canceling %s', t2.getName())
time.sleep(2)
logging.debug('canceling %s', t2.getName())
t2.cancel()
logging.debug('done')

Notice that the second timer is never run, and the first timer appears to run after the rest of the main program is done. Since it is not a daemon thread, it is joined implicitly when the main thread is done.

可以看到第二个timer从未运行过,而第一timer是在主程序退出以后才开始运行。因为它不是守护线程,被隐含的与主线程join

(MainThread) starting timers
(MainThread) waiting before canceling t2
(MainThread) canceling t2
(MainThread) done
>>> (t1        ) worker running

(我自己把delay时间也就是3换成了1,)

t1 = threading.Timer(1, delayed)
t1.setName('t1')
t2 = threading.Timer(1, delayed)
t2.setName('t2')

(结果如下)

(MainThread) starting timers
(MainThread) waiting before canceling t2
(t2        ) worker running
(t1        ) worker running
(MainThread) canceling t2
(MainThread) done



未完待续~~



--结束END--

本文标题: Threading in Python-

本文链接: https://www.lsjlt.com/news/186434.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Threading in Python-
    原文是2.x版本的,然后应该是英文的.我在学习的过程中,同时改成python 3.3并且改成中文,引入一些自己的理解.Thread Objects线程对象The simplest way to use a Thread is to inst...
    99+
    2023-01-31
    Threading Python
  • Python threading
     1.  第一种方式: 创建一个threading.Thread()的实例,给它一个函数。 import threading from time import sleep, ctime loops = [...
    99+
    2023-01-31
    Python threading
  • [python][threading][
        thread不支持守护线程,当主线程退出时,所有的子线程无条件推出;针对这种情况,threading引入了守护线程的概念。     如果主线程要退出的时候,不用等待子线程完成,那就在线程开始之前,即调用start()之前,调用set...
    99+
    2023-01-31
    python threading
  • Python中的threading
    #!/usr/bin/env python# -*- coding: utf-8 -*-import threading, time#新线程执行的代码:def loop():    print('thread %s is running.....
    99+
    2023-01-31
    Python threading
  • Python中threading的joi
    python的进程和线程经常用到,之前一直不明白threading的join和setDaemon的区别和用法,今天特地研究了一下。multiprocessing中也有这两个方法,同样适用,这里以threading的join和setDaem...
    99+
    2023-01-30
    Python threading joi
  • python多线程threading
    本文通过 4个example 介绍python中多线程package —— threading的常用用法, 包括调用多线程, 同步队列类Queue, Ctrl+c结束多线程。 example1. 调用10个线程, 分别打印0~...
    99+
    2023-01-31
    多线程 python threading
  • Python线程之threading
    线程是属于进程的,线程运行在进程空间内,同一进程所产生的线程共享同一内存空间,当进程退出时该进程所产生的线程都会被强制退出并清除。进程是资源分配的最小单位,线程是CPU调度的最小单位,每一个进程中至少有一个线程,线程可与属于同一进程的其它线...
    99+
    2023-01-31
    线程 Python threading
  • Python线程threading(Thread类)
    目录前言Python创建线程 threading调用Thread类的构造器创建线程继承Thread类创建线程类Thread join()用法前言 几乎所有的操作系统都支持同时运行多个...
    99+
    2024-04-02
  • python threading多线程p
    #!/usr/bin/env python                                                                                       #_*_coding:u...
    99+
    2023-01-31
    多线程 python threading
  • Python 多线程threading模
            首先,我们在了解多线程时需要理解的就是什么是多线程,按照官方的解释就是:多线程(英语:multithreading),是指从软件或者硬件上实现多个线程并发执行的技术。    在我自学到这里的时候,通过会在想进程和线程到底是有...
    99+
    2023-01-31
    多线程 Python threading
  • python 通过threading多线
    #!/usr/bin/env python#coding=utf-8import paramikoimport time,datetime,threadingdef ssh(ip,user,passwd,command):    ssh =...
    99+
    2023-01-31
    python threading 多线
  • python threading超线程使
    在工作过程中中,将内容过程中经常用的内容片段珍藏起来,下面内容段是关于python threading超线程使用简单范例的内容,希望能对小伙伴们有较大帮助。 # encoding: UTF-8 import threading # 方法1...
    99+
    2023-01-31
    超线程 python threading
  • python 包之 threading 多线程
    目录一、创建一个线程二、创建多个线程三、线程同步四、递归锁五、信号锁一、创建一个线程 通过实例化threading.Thread类创建线程 import threading def...
    99+
    2024-04-02
  • Python多线程threading用法
    Python里面经常会用到多线程,即所有的方法在同一时间开始运行,而不是按顺序一个一 个运行。所用到的模块为threading,下面详解threading用法。 我们写三个方法,one、two、three并正常运行。 这里只截图了one()...
    99+
    2023-01-31
    多线程 Python threading
  • Python中如何使用threading
    Python中如何使用threading,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。  Python 版本是3.7.4  前面的文章记录了网络请求(urllib,requ...
    99+
    2023-06-02
  • Python 多线程之 threading 模块
    在之前的文章中,我们已经介绍了 Python 通过 _thread 和 threading 模块提供了对多线程的支持,threading 模块兼具了 _thread 模块的现有功能,又扩展了一些新的功能,具有十分丰富的线程操作功能,本节我们...
    99+
    2023-09-16
    python 开发语言 java
  • python threading模块的使用指南
    目录1. threding模块创建线程对象2. threding模块创建多线程3. 多线程的参数传递4. 线程产生的资源竞争1. threding模块创建线程对象 接上述案例,我们可以利用程序阻塞的时间让程序执行后...
    99+
    2022-06-02
    python threading模块 python threading的使用
  • python 多线程threading程序详情
    CPython implementation detail: 在 CPython 中,由于存在全局解释器锁, 同一时刻只有一个线程可以执行 Python 代码(虽...
    99+
    2024-04-02
  • python中threading模块怎么使用
    python中threading模块详解,threading提供了一个比thread模块更高层的API来提供线程的并发性。这些线程并发运行并共享内存。下面来看threading模块的具体用法:一、Thread的使用目标函数可以实例化一个Th...
    99+
    2023-05-15
    Python threading
  • 浅谈一下python中threading模块
    目录一、Thread的使用二、threading.activeCount()的使用三、threading.enumerate()的使用。四、threading.setDaemon()...
    99+
    2023-05-18
    python threading threading模块
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作