iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >线程、进程、协程和GIL(三)
  • 821
分享到

线程、进程、协程和GIL(三)

线程进程GIL 2023-01-30 23:01:05 821人浏览 安东尼

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

摘要

上一篇文章介绍了:创建线程的两种方式、Event对象判断线程是否启动、利用信号量控制线程并发。 博客链接:线程、进程、协程和GIL(二) 这一篇来说说线程间通信的那些事儿:    一个线程向另一个线程发送数据最安全的方式就是使用queue

上一篇文章介绍了:创建线程的两种方式、Event对象判断线程是否启动、利用信号量控制线程并发

博客链接:线程、进程、协程和GIL(二)

这一篇来说说线程间通信的那些事儿: 

  一个线程向另一个线程发送数据最安全的方式就是使用queue库中的队列了,通过创建一个供多个线程共享的Queue对象,这些线程使用put()和get()操作来向队列中添加数据或者从队列中取出数据,以达到线程间通信的效果。

  queue队列基本方法:

    queue.Queue(maxsize = num):  FIFO  先进先出队列,如果maxsize小于或等于0 则代表队列长度无线。

    queue.LifoQueue(maxsize = num): LIFO 后进先出队列(类似于栈),如果maxsize小于或等于0 则代表队列长度无线。

    Queue.qsize(): 返回当前队列中元素的个数

         Queue.empty()   如果队列为空,返回True,反之False 

         Queue.full()   如果队列满了,返回True,反之False

         Queue.get([block[, timeout]])   读队列,timeout等待时间 

         Queue.put(item, [block[, timeout]])   写队列,timeout等待时间 

         Queue.queue.clear()   清空队列

  使用Queue构造生产者消费者模型来实现线程间的通信:

import time
from queue import Queue,LifoQueue
from threading import Thread

def producer(in_q):
    while True:
        time.sleep(1)
        data = '包子'
        if in_q.full() == True:
            print('蒸笼满了,放不下了')
        in_q.put(data)  # 向队列中塞东西
        print('小明蒸%s!' %(data))

def customer(out_q):
    while True:
        time.sleep(3)
        if out_q.empty() == True:
                print('小红没取到包子,饿死了!')
        data = out_q.get() # 从队列中取东西
        print('小红取 %s ' % (data))

if __name__ == '__main__':
    q = Queue(maxsize=3)
    t1 = Thread(target=producer, args=(q,))
    t2 = Thread(target=customer, args=(q,))
    t1.start()
    t2.start()

  上面的代码实现了一个简单的生产者消费者,小明负责蒸包子,小红负责吃包子。当队列被包子塞满时,小明就再也放不进去了,此时生产者这个线程就会阻塞。当小红将队列中的包子吃完时,消费者这个线程就会阻塞。因为Queue对象已经封装了必要的,所以我们可以在多个线程之间安全的功能共享数据。但是在生产者消费者的关闭问题会有一些麻烦,通用的解决方式就是在队列中放置一个特殊值,当消费者读到这个值时,就终止执行。

  不过有个问题需要注意:向队列中添加数据项时,并不会复制此数据项,线程间的通信实际上是在线程间传递对象引用。如果你单线对象的共享状态,那么最好只传递不可修改的数据结构(如:整型、字符串、或者元组)或者一个对象的深拷贝。

  给关键部分加锁

  线程的不安全:同一进程里线程是共享数据的,当各个线程访问同一个数据资源时会出现竞争状态,即数据可能会同时被多个线程占用,造成数据混乱,这就是线程的不安全。

   为了保证线程安全,所以引进了互斥锁,确保某段关键代码、共享数据只能由一个线程从头到尾完整地执行:

  显式的加锁:

from threading import Thread, Lock

num = 0
lock = Lock()  # 定义一个锁

def run():
    global num, lock  # 获取全局变量
    lock.acquire()  # 加锁
    num += 1
    print(num)
    lock.release()  # 释放锁

if __name__ == '__main__':
    Thread_list = []
    for i in range(1000):
        t = Thread(target=run)
        Thread_list.append(t)
    for i in Thread_list:
        i.start()

  死锁:但是加入互斥锁之后有可能会产生一个问题:死锁:若干子线程在系统资源竞争时,都在等待对方对某部分资源解除占用状态,结果谁也不愿意先解锁,互相等着,程序无法执行下去,这就是死锁。

  比如:有两个线程一、二,两个共享资源A、B,线程一给资源A加锁,线程二给资源B加锁,然后资源A需要访问资源B,资源B需要调用资源A,线程一二双方都在等待对方释放锁,所以就会造成死锁。

   But、当程序员在加锁之后忘记调用release()方法,或者加锁之后程序抛异常导致不能正常释放锁,有可能会造成死锁,为了避免这种情况,我们不需要显式的手动加锁和释放锁,而是使用with语句来进行自动控制:

  

from threading import Thread, Lock

num = 0
lock = Lock()  # 定义一个锁

def run():
    global num, lock
    with lock:  # 自动的控制加锁和释放锁
        num += 1
        print(num)

if __name__ == '__main__':
    Thread_list = []
    for i in range(1000):
        t = Thread(target=run)
        Thread_list.append(t)
    for i in Thread_list:
        i.start()

  创建一个线程池: 

  concurrent.futures 函数库有一个 ThreadPoolExecutor 类可以被用来完成这个任务

from concurrent.futures import ThreadPoolExecutor

def run():
    print('我是子线程')

if __name__ == '__main__':
    pool = ThreadPoolExecutor(max_workers=3)  # 创建一个容量为3的线程池
    for i in range(3):
        t = pool.submit(run,)  #在线程池中生成三个线程,他们都来调用run方法
    print('我是主线程')

 

想了解更多python关于爬虫数据分析的内容,欢迎大家关注我的微信公众号:悟道Python

  

--结束END--

本文标题: 线程、进程、协程和GIL(三)

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

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

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

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

下载Word文档
猜你喜欢
  • 线程、进程、协程和GIL(三)
    上一篇文章介绍了:创建线程的两种方式、Event对象判断线程是否启动、利用信号量控制线程并发。 博客链接:线程、进程、协程和GIL(二) 这一篇来说说线程间通信的那些事儿:    一个线程向另一个线程发送数据最安全的方式就是使用queue...
    99+
    2023-01-30
    线程 进程 GIL
  • Python进程/线程/协程
    第1章 操作系统历史1.1为什么要有操作系统?程序员无法把所有的硬件操作细节全部了解到,管理这些硬件并且加以优化使用时非常繁琐的工作,这个繁琐的工作就是由操作系统来干的,有了它,程序员就从这些繁琐的工作中解脱了出来,只需要考虑自己的应用软件...
    99+
    2023-01-31
    线程 进程 Python
  • 异步 PHP — 多进程、多线程和协程
    让我们看一下这段典型的 PHP 代码: function names(){ $data = Http::get('data.location/products')->json(); $names = []; foreach...
    99+
    2023-09-09
    servlet json java
  • Python进程与线程及GIL(全局解释
    MarkdownPad Document程序并不能单独运行,只有将程序装载到内存中,系统为它分配资源才能运行,而这种一个程序在一个数据集上的一次动态执行过程就称之为进程。程序和进程的区别就在于:程序是指令的集合,它是进程运行的静态描述文本;...
    99+
    2023-01-31
    线程 全局 进程
  • Python进程/线程/协程相关
    1、获取进程ID。(getpid)os.getpid()2、获取父进程ID。(getppid)os.getppid()3、获取线程ID。(get_ident)(1)、进程内局部标识。import threading threading.ge...
    99+
    2023-01-31
    线程 进程 Python
  • 什么是进程、线程、协程
    什么是进程? 我们都知道计算机的核心是CPU,它承担了所有的计算任务;而操作系统是计算机的管理者,它负责任务的调度、资源的分配和管理,统领整个计算机硬件;应用程序则是具有某种功能的程序,程序是运行于操...
    99+
    2023-09-06
    java jvm linux
  • Python:线程、进程与协程(7)——
         前面转载了一篇分析进程池源码的博文,是一篇分析进程池很全面的文章,点击此处可以阅读。在Python中还有一个线程池的概念,它也有并发处理能力,在一定程度上能提高系统运行效率;不正之处欢迎批评指正。     线程的生命周期可以分为5...
    99+
    2023-01-31
    线程 进程 Python
  • Python:线程、进程与协程(3)——
        Queue模块是提供队列操作的模块,队列是线程间最常用的交换数据的形式。该模块提供了三种队列:Queue.Queue(maxsize):先进先出,maxsize是队列的大小,其值为非正数时为无线循环队列Queue.LifoQueue...
    99+
    2023-01-31
    线程 进程 Python
  • 实例详解Python的进程,线程和协程
    目录前言前提条件相关介绍实验环境进程多进程用进程池对多进程进行操作线程使用_thread模块实现使用 threading 模块实现协程使用asyncio模块实现总结前言 本文用Pyt...
    99+
    2024-04-02
  • Python的进程,线程和协程实例分析
    这篇“Python的进程,线程和协程实例分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Python的进程,线程和协程实例...
    99+
    2023-06-29
  • Python:线程、进程与协程(1)——
            最近的业余时间主要放在了学习Python线程、进程和协程里,第一次用python的多线程和多进程是在两个月前,当时只是简单的看了几篇博文然后就跟着用,没有仔细去研究,第一次用的感觉它们其实挺简单的,最近这段时间通过看书, 看...
    99+
    2023-01-31
    线程 进程 Python
  • Python:线程、进程与协程(6)——
        上篇博文介绍了multiprocessing模块的内存共享(点击此处可以参看),下面讲进程池。有些情况下,所要完成的工作可以上篇博文介绍了multiprocessing模块的内存共享,下面讲进程池。有些情况下,所要完成的工作可以分解...
    99+
    2023-01-31
    线程 进程 Python
  • Python:线程、进程与协程(2)—
        上一篇博文介绍了Python中线程、进程与协程的基本概念,通过这几天的学习总结,下面来讲讲Python的threading模块。首先来看看threading模块有哪些方法和类吧。主要有:Thread :线程类,这是用的最多的一个类,...
    99+
    2023-01-31
    线程 进程 Python
  • Python的进程,线程和协程实例详解
    目录相关介绍实验环境进程多进程用进程池对多进程进行操作线程使用_thread模块实现使用 threading 模块实现协程使用asyncio模块实现总结相关介绍 Python是一种跨...
    99+
    2024-04-02
  • 一文搞懂Python中的进程,线程和协程
    目录1.什么是并发编程2.进程与多进程3.线程与多线程4.协程与多协程5.总结1.什么是并发编程 并发编程是实现多任务协同处理,改善系统性能的方式。Python中实现并发编程主要依靠...
    99+
    2024-04-02
  • 怎么理解进程,线程,协程
    本篇内容介绍了“怎么理解进程,线程,协程”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!进程进程是操作系统分...
    99+
    2024-04-02
  • 多任务中进程、线程、协程
    为什么使用多任务有什么好处? 答:提高程序执行效率,实现同一时刻可以做二个以上的事情。 啦啦啦。。。重点来了 并行:任务数大于CPU核数,每个CPU就要执行多个任务,那肯定忙不过来,多个任务执行就需要排队等待上一任务执行完,才能执行下一任...
    99+
    2023-01-30
    线程 进程 协程
  • swoole协程是进程还是线程
    今天小编给大家分享一下swoole协程是进程还是线程的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。swoole协程是属于线程...
    99+
    2023-06-29
  • 掌握 Python 并发编程:揭秘协程、线程和进程
    并发编程是编写同时执行多个任务的代码的艺术,在 Python 中提供了协程、线程和进程等多种选项。了解这些选项及其适用场景对于开发高效、可扩展的应用程序至关重要。 协程 协程是 Python 中一种轻量级的并发机制,允许一个函数暂停执行...
    99+
    2024-02-18
    协程 线程 进程 并发 Python
  • Golang 协程 / 线程 / 进程 区别详解
    概念进程 每个进程都有自己的独立内存空间,拥有自己独立的地址空间、独立的堆和栈,既不共享堆,亦不共享栈。一个程序至少有一个进程,一个进程至少有一个线程。进程切换只发生在内核态。线程 线程拥有自己独立的栈和共享的堆,共享堆,不共享栈,是由操作...
    99+
    2023-06-08
    Go istio k8s 云原生
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作