广告
返回顶部
首页 > 资讯 > 后端开发 > Python >Python多线程编程
  • 521
分享到

Python多线程编程

多线程Python 2023-01-31 07:01:42 521人浏览 泡泡鱼

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

摘要

  一个串行程序需要从每个I/O终端通道来检测用户的输入,然而程序在读取过程中不能阻塞,因为用户输入的到达时间的不确定,并且阻塞会妨碍其他I/O通道的处理。由于串行程序只有唯一的执行线程,因此它需要兼顾执行的多个任务,确保其中的某个任务不会

  一个串行程序需要从每个I/O终端通道来检测用户的输入,然而程序在读取过程中不能阻塞,因为用户输入的到达时间的不确定,并且阻塞会妨碍其他I/O通道的处理。由于串行程序只有唯一的执行线程,因此它需要兼顾执行的多个任务,确保其中的某个任务不会占用过多的时间,并对用户的响应时间进行合理的分配。这种任务类型的串行程序的使用,往往造成非常复杂的控制流,难以维护。

   多线程编程的本质就是异步,需要多个并发活动,每个活动的处理顺序不确定,或者说随机的。这种编程任务可以被组织或划分成多个执行流,其中每个执行流都有一个指定要完成的任务。根据应用的不同,这些子任务可能需要计算出中间结果,然后合并为最终的输出。使用多线程编程,以及类似的Queue的共享数据结构,这个编程任务可以规划成几个特定函数的线程。使用多线程编程来规划这种编程任务可以降低程序的复杂度,使其实现更加清晰、高校,简洁。

  • 进程与线程

  计算机程序只是存储在磁盘上的可执行二进制文件。只有把它们加载到内存中并操作系统调用,才能拥有其生命周期。进程则是一个执行中的程序。每个进程都有自己的地址空间、内存、数据栈以及其他用于跟踪执行的辅助数据。进程可以通过派生(fork或spawn)新的进程来执行其他任务,但是因为每个新进程也拥有自己的内存和数据栈等,所以只能采用进程间通信(IPC)的方式共享信息。

  线程与进程类似,不过它们是在同一进程下执行的,并共享相同的上下文。一个进程中的各个线程与主线程共享同一片数据空间,因此相比于独立的进程而言,线程间的共享和通信更加容易。线程一般以并行方式执行,正是由于这种并行和数据共享,是的多任务的协作成为可能。但是线程建的数据共享可能引起多个线程访问同一片数据造成竞态条件,而且多个线程无法给与公平的执行时间。

  • 全局解释锁

  python的代码执行是由Python虚拟机(解释器主循环)进行控制。在主循环中同时只有一个控制线程在执行,就像单核CPU系统中的多线程一样。内存中可以有许多程序,但是任意给定的时刻只能有一个程序在运行。同理,尽管Python解释其中可以运行多个线程,但任意时刻只有一个线程会被解释器执行。

  对Python虚拟机的访问是由全局解释(GIL)控制的。这个锁就是用来保证同时只能有一个线程运行。在多线程环境中,Python虚拟机将按照以下方式执行:

1.设置GIL

2.切换到一个线程去运行

3.运行:
  a. 指定数量的字节码指令

  b. 线程主动让出控制(调用time.sleep(0))

4.把线程设置为睡眠状态
5.解锁GIL
6.再次重复以上所有步骤 

  • Python中的threading模块

 Python提供了多个模块来支持来支持多线程编程,包括thread、threading和Queue模块等。然而建议避免使用thread模块,threading模块更加先进,有更好的线程支持,并且thread模块中一些属性会和threading冲突,另外低级别的thread模块拥有的同步原语和很少。更重要的是,在python3中已经没有thread模块。


thread模块和锁对象

thread模块的函数

start_new_thread(function, args[, kwargs])派生一个新的线程
allocate_lock()分配LockType锁对象
exit()线程退出

LockType锁对象的方法

acquire(wait=None)尝试获取锁对象
locked()如果获取锁对象返回True,否则False
release()释放锁

threading模块

threading模块的对象


对象描述
Thread一个线程的执行对象
Lock锁原语对象
RLock可重入锁对象,使单一线程(再次)获得已持有的锁(递归锁)
Condition条件变量对象,使得一个线程等待另一个线程满足特定的条件
Event
条件变量的通用版本,任意数量的线程等待某个事件的发生,该事件发生后所有线程将激活
Semaphore

为线程间共享的有限资源提供'计数器',如果没有可用资源时会被阻塞

BoundedSemaphore
与Semaphore相似,但它不允许超过初始值
Timer
与Thread相似,在运行前需要等待一段时间
Barrier
创建一个'障碍',必须达到指定数量线程后才可以继续

Thread对象数据属性

name线程名
ident线程标识符
daemon布尔标志,表示这个线程是否是守护线程

Thread对象方法

__init__(self, group=None, target=None, name=None, args=(), kwargs=None, *, daemon=None)实例化一个线程
start(self)开始执行该线程
run(self)定义线程功能的方法
join(self, timeout=None)直至启动的线程终止之前一直挂起,除非给出了timeout,否则一直阻塞
getName(self)返回线程名
setName(self, name)设定线程名
isAlive()/is_alive(self)布尔标志,表示线程是否还存活
isDaemon(self)如果是守护线程,返回True
setDaemon(self, daemonic)把线程的守护标志设定为deamonic(必须在线程start()之前调用)

  使用Thread类,可以有很多方法创建线程,有三种常用的方法:

创建Thread的实例,传给它一个函数

创建Thread的实例,传给它一个可调用的类实例

派生Thread的子类,并创建子类的实例

创建Thread的实例,传给它一个函数:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
'''
join()方法,可以等待所有线程执行完毕
'''
import threading
from time import sleep,ctime
loops = [4,2]
def loop(nloop,nsec):
    print('start loop',nloop,'at:',ctime())
    sleep(nsec)
    print('loop',nloop,'done at:',ctime())
def main():
    print('starting at:',ctime())
    threads = []
    nloops = range(len(loops))
    for i in nloops:
        t = threading.Thread(target=loop,args=(i,loops[i]))
        threads.append(t)
    for i in nloops:
        threads[i].start()
    for i in nloops:
        threads[i].join()
    print('all DONE at:',ctime())
if __name__ == '__main__':
    main()

运行结果:
starting at: Wed May 10 12:30:28 2017
start loop 0 at: Wed May 10 12:30:28 2017
start loop 1 at: Wed May 10 12:30:28 2017
loop 1 done at: Wed May 10 12:30:30 2017
loop 0 done at: Wed May 10 12:30:32 2017
all DONE at: Wed May 10 12:30:32 2017

创建Thread的实例,传给它一个可调用的类实例:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import threading
from time import sleep,ctime
loops = [4,2]
class ThreadFunc(object):
    def __init__(self,func,args,name=''):
        self.name = name
        self.func = func
        self.args = args
    def __call__(self):
        self.func(*self.args)
def loop(nloop,nsec):
    print('start loop',nloop,'at:',ctime())
    sleep(nsec)
    print('loop',nloop,'done at:',ctime())
def main():
    print('starting at:',ctime())
    threads = []
    nloops = range(len(loops))
    for i in nloops:
        t = threading.Thread(target=ThreadFunc(loop,(i,loops[i]),loop.__name__))
        threads.append(t)
    for i in nloops:
        threads[i].start()
    for i in nloops:
        threads[i].join()
    print('all DONE at:',ctime())
if __name__ == '__main__':
    main()
运行结果:
starting at: Wed May 10 12:31:23 2017
start loop 0 at: Wed May 10 12:31:23 2017
start loop 1 at: Wed May 10 12:31:23 2017
loop 1 done at: Wed May 10 12:31:25 2017
loop 0 done at: Wed May 10 12:31:27 2017
all DONE at: Wed May 10 12:31:27 2017

派生Thread的子类,并创建子类的实例

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import threading
from time import sleep,ctime

loops = (4,2)
class MyThread(threading.Thread):
    def __init__(self,func,args,name=''):
        threading.Thread.__init__(self)
        self.name = name
        self.func = func
        self.args = args
    def run(self):
        self.func(*self.args)
def loop(nloop,nsec):
    print('start loop',nloop,'at:',ctime())
    sleep(nsec)
    print('loop',nloop,'done at:',ctime())

def main():
    print('starting at:',ctime())
    threads = []
    nloops = range(len(loops))

    for i in nloops:
        t = MyThread(loop,(i,loops[i]),loop.__name__)
        threads.append(t)
    for i in nloops:
        threads[i].start()
    for i in nloops:
        threads[i].join()
    print('all DONE at:',ctime())

if __name__ == '__main__':
    main()
运行结果:
starting at: Wed May 10 10:43:10 2017
start loop 0 at: Wed May 10 10:43:10 2017
start loop 1 at: Wed May 10 10:43:10 2017
loop 1 done at: Wed May 10 10:43:12 2017
loop 0 done at: Wed May 10 10:43:14 2017
all DONE at: Wed May 10 10:43:14 2017

锁的使用

  锁有两种状态:锁定和未锁定。而且它也只支持两个函数,获得锁和释放锁。当多线程争夺锁时,允许第一个获得锁的线程进入临界区,并执行代码。所有之后到达的线程将被阻塞,直到第一个线程之行结束,退出临界区,并释放锁。此时,其他等待的线程可以获得锁并进入临界区,不过那些被阻塞的线程进入临界区没有先后顺序,根据Python实现不同而有所区别。

#!/usr/bin/env python
# -*- coding:utf-8 -*-

from atexit import reGISter
from  random import randrange
from threading import Thread,Lock,current_thread
from time import sleep,ctime

class CleanOutputSet(set):
    def __str__(self):
        return ','.join(x for x in self)
lock = Lock()
loops = (randrange(2,5) for x in range(randrange(3,7)))
remaining = CleanOutputSet()

def loop(nsec):
    myname = current_thread().name
    lock.acquire()
    remaining.add(myname)
    print('[%s] started %s' %(ctime(),myname))
    lock.release()
    sleep(nsec)
    lock.acquire()
    remaining.remove(myname)
    print('[%s] completed %s (%d secs)' %(ctime(),myname,nsec))
    print('(remaining:%s)' %(remaining or 'None'))
    lock.release()

def main():
    for pause in loops:
        Thread(target=loop,args=(pause,)).start()

@register
def _atexit():
    print('all DONE at:',ctime())

if __name__ == '__main__':
    main()
    
运行结果:
[Wed May 10 11:20:14 2017] started Thread-1
[Wed May 10 11:20:14 2017] started Thread-2
[Wed May 10 11:20:14 2017] started Thread-3
[Wed May 10 11:20:16 2017] completed Thread-3 (2 secs)
(remaining:Thread-2,Thread-1)
[Wed May 10 11:20:16 2017] completed Thread-2 (2 secs)
(remaining:Thread-1)
[Wed May 10 11:20:18 2017] completed Thread-1 (4 secs)
(remaining:None)
all DONE at: Wed May 10 11:20:18 2017

信号量的使用

 信号量是最古老的同步原语之一。它是一个计数器,当资源消耗时递减,当资源释放时递增。信号量比锁更加灵活,因为可以有多个线程,每个线程拥有有限资源的一个实例。

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from atexit import register
from random import randrange
from threading import BoundedSemaphore,Lock,Thread
from time import sleep,ctime

lock = Lock()
MAX = 5
candytray = BoundedSemaphore(MAX)

def refill():
    lock.acquire()
    print('Refilling candy...')
    try:
        candytray.release()
    except ValueError:
        print('full,skipping')
    else:
        print('OK')
    lock.release()

def buy():
    lock.acquire()
    print('Buying candy...')
    if candytray.acquire(False):
        print('OK')
    else:
        print('empty,skipping')
    lock.release()

def producer(loops):
    for i in range(loops):
        refill()
        sleep(randrange(3))
def consumer(loops):
    for i in range(loops):
        buy()
        sleep(randrange(3))

def main():
    print('starting at:',ctime())
    nloops = randrange(2,6)
    print('THE CANDY MacHINE ( full with %d bars)'%MAX)
    Thread(target=consumer,args=(randrange(nloops,nloops+MAX+2),)).start()
    Thread(target=producer,args=(nloops,)).start()

@register
def _atexit():
    print('all DONE at:',ctime())

if __name__ == '__main__':
    main()
    
运行结果:
starting at: Wed May 10 11:42:34 2017
THE CANDY MACHINE ( full with 5 bars)
Buying candy...
OK
Refilling candy...
OK
Refilling candy...
full,skipping
Buying candy...
OK
Refilling candy...
OK
Refilling candy...
full,skipping
Buying candy...
OK
Refilling candy...
OK
Buying candy...
OK
Buying candy...
OK
Buying candy...
OK
Buying candy...
OK
Buying candy...
OK
Buying candy...
empty,skipping
Buying candy...
empty,skipping
Buying candy...
empty,skipping
all DONE at: Wed May 10 11:42:44 2017
  • 生产者-消费者问题和Queue/queue

queue模块的类

Queue(maxsize=0)创建一个先入先出队列。如果给定最大值,在队列没有空间时阻塞,否则为无限队列
LifoQueue(maxsize=0)创建一个后入先出队列。如果给定最大值,在队列没有空间时阻塞,否则为无限队列
PriorityQueue(maxsize=0)创建一个优先级队列。如果给定最大值,在队列没有空间时阻塞,否则为无限队列

queue异常

Empty当对空队列调用get()方法时抛出异常
Full当对满队列调用put()方法时抛出异常

queue对象方法

qsize()返回队列大小
empty()如果队列为空,则返回True
full()如果队列为满,则返回True
put(item,block=True,timeout=None)将item放入队列,如果block为True且timeout为None,则在有可调用空间之前阻塞;如果timeout为正值 ,则最多阻塞timeout秒,如果block为False,则抛出Empty异常
put_nowait(item)
和put(item,False)相同
get(block=True,timeout=None)从队列中取得元素,如果给定block(非0),则一直阻塞到有可用元素为止
get_nowait(item)和get(False)相同
task_done()

表示队列中的某个元素已经完成,该方法会被

join()使用

join()
在队列所有元素执行完毕并调用task_done信号之前, 保持阻塞。
#!/usr/bin/env python
# -*- coding:utf-8 -*-

import threading
import time
from queue import Queue
import random
class consumer(threading.Thread):
    def __init__(self, que):
        threading.Thread.__init__(self)
        self.queue = que
    def run(self):
        while True:
            if self.queue.empty():
                break
            item = self.queue.get()
            #processing the item
            time.sleep(item)
            print(self.name,item)
            self.queue.task_done()
        return
que = Queue()
for x in range(10):
    number = random.randint(1, 5)
    print('random %d number is %d:' % (x, number))
    que.put(number, True, None)
print('queue is:', que.queue)
consumers = [consumer(que) for x in range(5)]

for c in consumers:
    c.start()
que.join()

运行结果:
random 0 number is 5:
random 1 number is 1:
random 2 number is 2:
random 3 number is 1:
random 4 number is 5:
random 5 number is 3:
random 6 number is 3:
random 7 number is 2:
random 8 number is 2:
random 9 number is 2:
queue is: deque([5, 1, 2, 1, 5, 3, 3, 2, 2, 2])
Thread-2 1
Thread-4 1
Thread-3 2
Thread-3 2
Thread-2 3
Thread-4 3
Thread-1 5
Thread-5 5
Thread-3 2
Thread-2 2


--结束END--

本文标题: Python多线程编程

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

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

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Python多线程编程
      一个串行程序需要从每个I/O终端通道来检测用户的输入,然而程序在读取过程中不能阻塞,因为用户输入的到达时间的不确定,并且阻塞会妨碍其他I/O通道的处理。由于串行程序只有唯一的执行线程,因此它需要兼顾执行的多个任务,确保其中的某个任务不会...
    99+
    2023-01-31
    多线程 Python
  • python 多线程编程
    使用回调方式 import time def countdown(n): while n > 0: print('T-minus', n) n -= 1 time.sleep...
    99+
    2023-01-31
    多线程 python
  • Python多线程编程,线程锁
    多线程threading 模块创建线程创建自己的线程类线程通信线程同步互斥方法线程锁@需要了解!!!   什么是线程? 线程也是一种多任务的编程方法,可以利用计算机多核资源完成程序的并发运行。 线程又被称为轻量级进程 ...
    99+
    2023-01-30
    线程 多线程 Python
  • python多线程socket编程--多
    Python中实现socket通信的服务端比较复杂,而客户端非常简单,所以客户端基本上都是用sockct模块实现,而服务 端用有很多模块可以使用,如下: 1、客户端 #!/usr/bin/env python #coding...
    99+
    2023-01-31
    多线程 python socket
  • Python多线程编程实例
    Python多线程编程 发布者:lanyulei,转载请注明出处:http://www.fdevops.com/p=517 下面多线程模块threading的方法注释,均来自于百度贴吧"学点编程吧"。 Thread: 表示一个线程的执行对象...
    99+
    2023-01-31
    多线程 实例 Python
  • python并发编程之多线程编程
    一、threading模块介绍 multiprocess模块的完全模仿了threading模块的接口,二者在使用层面,有很大的相似性,因而不再详细介绍 二、开启线程的两种方式 方式一: from threading import ...
    99+
    2023-01-31
    之多 线程 python
  • Python多线程编程入门详解
    目录一、任务、进程和线程任务进程线程进程和线程的关系二、Python既支持多进程,又支持多线程Python实现多进程Process进程类的说明Python实现多线程线程类Thread...
    99+
    2022-11-12
  • 深入理解python多线程编程
    进程 进程的概念: 进程是资源分配的最小单位,他是操作系统进行资源分配和调度运行的基本单位。通俗理解:一个正在运行的一个程序就是一个进程。例如:正在运行的qq、wechat等,它们都...
    99+
    2022-11-12
  • python多线程编程:如何优雅地关闭线程
    在并发编程中,我们可能会创建新线程,并在其中运行任务,可能由于一些原因,决定停止该线程。例如: 不再需要线程任务的结果了。应用程序正在关闭。线程执行可能已经出现了异常 关于python多线程编程知...
    99+
    2023-09-04
    python 开发语言
  • Java 多线程编程
    Java 多线程编程   目录 Java 多线程编程 一个线程的生命周 线程的优先级 创建一个线程 通过实现Runnable接口来创建线程 实例 通过继承Thread来创建线程 实例 Thread 方法 实例   线程的几个主要概念: 多线...
    99+
    2023-10-20
    python 开发语言
  • python3 多线程编程
    0.什么是线程 多线程模块 创建线程的方法 join()方法 4.isAlive()方法 name属性和daemon属性 6.线程的同步---锁 7.线程的同步---Event对象 8.线程的同步---Condition条件...
    99+
    2023-01-31
    多线程
  • 多线程编程(3):线程池ThreadPo
    在面向对象编程中,经常会面对创建对象和销毁对象的情况,如果不正确处理的话,在短时间内创建大量对象然后执行简单处理之后又要销毁这些刚刚建立的对象,这是一个非常消耗性能的低效行为,所以很多面向对象语言中在内部使用对象池来处理这种情况,以提高性能...
    99+
    2023-01-31
    线程 多线程 ThreadPo
  • Python中的多进程编程和多线程编程的区别是什么?
    Python中的多进程编程和多线程编程的区别是什么?在Python中,多进程编程和多线程编程都是实现并行计算的方法。虽然它们都能同时运行多个任务,但其底层原理和使用方式却有所不同。多进程编程是利用操作系统的多进程机制来实现并行计算的。在Py...
    99+
    2023-10-22
    多进程编程 多线程编程 区别
  • python线程编程
    1、线程模式代码#!/usr/bin/python #_*_coding:utf-8_*_ import threading import time def Producer():     print 'chef : 等人来买包子。。...
    99+
    2023-01-31
    线程 python
  • python多线程————3、多线程间通
    1、共享变量 #通过共享变量 import time import threading url_list = [] def get_detail_html(): global url_list while True: ...
    99+
    2023-01-31
    多线程 python
  • Python 多线程
      文章来源:https://www.runoob.com/python/python-multithreading.html 多线程类似于同时执行多个不同程序,多线程运行有如下优点: 使用线程可以把占据长时间的程序中的...
    99+
    2023-01-31
    多线程 Python
  • python多线程
    Python 多线程 多线程类似于同时执行多个不同程序,多线程运行有如下优点: 使用线程可以把占据长时间的程序中的任务放到后台去处理。 用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的...
    99+
    2023-01-30
    多线程 python
  • python—多线程
    一、多线程实例  线程时应用程序中工作的最小单位,python中提供了threading模块来对多线程操作,一般多核cpu采用多进程方式,单核才采用多线程方式  方法:  将要执行的方法threading.Thread作为参数传给构造方法(...
    99+
    2023-01-31
    多线程 python
  • 如何使用Python中的多线程编程
    如何使用Python中的多线程编程,需要具体代码示例引言:随着计算机技术的不断发展,多核处理器的普及以及大数据时代的到来,多线程编程变得越来越重要。多线程编程可以充分利用计算机的多个核心,加快程序的执行速度,提高系统的响应性能。Python...
    99+
    2023-10-22
    Python多线程编程
  • Python多线程编程之threading模块详解
    目录一、介绍二、Python如何创建线程2.1 方法一:2.2 方法二:三、线程的用法3.1 确定当前的线程3.2 守护线程3.3 控制资源访问一、介绍 线程是什么?线程有啥用?线程...
    99+
    2022-11-12
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作