python多线程

7、线程、进程、协程进阶篇

纵饮孤独 提交于 2020-02-22 15:08:09
1.1.继上一讲,知道了如何创建多线程和GIL的原理,接下来要说的是线程锁,那为什么需要线程锁呢? 先看下图,此图来自:http://www.cnblogs.com/alex3714/articles/5230609.html,我就不自己动手画了,比我画得好 分析: (1)线程1拿到count=0并获得GIL,依次执行1,2,3,4,5,然后执行时间到了释放GIL (2)线程2拿到count=0并获得GIL,依次执行6,7,8,9,10,11,修改count的值,此时count的值由0变成1,并释放GIL (3)线程1再次拿到GIL并继续执行12,13,修改count的值,count的值还是1 问题出现了:线程1和线程2都把count+1,但是最后count的值还是1 线程锁:cpu在执行任务时,在线程之间是进行随机调度的,并且每个线程在执行一段时间之后会切换到另外一个线程,但是由于线程之间堆数据是共享的,所以就会有可能出现上述问题。 没加锁时的代码: # -*- coding: utf-8 -*- #__author:jiangjing #date:2018/2/4 #!/usr/bin/env python # -*- coding:utf-8 -*- import threading import time NUM = 0 def func(): global NUM

python多线程结合Queue使用

醉酒当歌 提交于 2020-02-21 19:04:03
python多线程结合Queue使用 大家好,我是W 前言:相信大家在做多线程的时候肯定都会想到结合Queue来用,那么到底怎么用呢?这篇文章来探索一下。 学习Queue 引用库 from queue import Queue 声明队列 q = Queue(maxsize=) q = Queue() # maxsize=:表示队列大小最大值,当队列到达最大值时再插入则线程会挂起 # 可不填,不填则理论无上限 Create a queue object with a given maximum size. If maxsize is <= 0, the queue size is infinite. 压入队列、弹出队列 q.put(item,block=True,timeout=None) # item:表示需要压入队列的对象 # block=True:表示当队列满时是否阻塞,默认为True # timeout=None:表示若需要阻塞,则阻塞多长时间,秒为单位 q.get(block=True,timeout=None) # 当使用该函数时将会从队列中弹出一个对象(FIFO原则),并且队列中的对象不再存在 # block=:表示当队列中无对象时是否阻塞,默认为True # timeout=:表示阻塞时长 q.get_nowait() # 该函数无参数 # 从队列中弹出一个对象

python多线程-Semaphore(信号对象)

孤者浪人 提交于 2020-02-18 10:56:55
Semaphore(value=1) Semaphore 对象内部管理一个计数器,该计数器由每个 acquire() 调用递减,并由每个 release() 调用递增。计数器永远不会低于零,当 acquire() 发现计数器为零时,线程阻塞,等待其他线程调用 release() 。 Semaphore 对象支持上下文管理协议。 方法: acquire(blocking=True, timeout=None) 获取信号。 当 blocking=True 时:如果调用时计数器大于零,则将其减1并立即返回。如果在调用时计数器为零,则阻塞并等待,直到其他线程调用 release() 使其大于零。这是通过适当的互锁来完成的,因此如果多个 acquire() 被阻塞, release() 将只唤醒其中一个,这个过程会随机选择一个,因此不应该依赖阻塞线程的被唤醒顺序。 返回值为 True 。 当 blocking=False 时,不会阻塞。如果调用 acquire() 时计数器为零,则会立即返回 False . 如果设置了 timeout 参数,它将阻塞最多 timeout 秒。如果在该时间段内没有获取锁,则返回 False ,否则返回 True 。 release() 释放信号,使计数器递增1。当计数器为零并有另一个线程等待计数器大于零时,唤醒该线程。 BoundedSemaphore

多线程同步和优先级队列(Queue)

假如想象 提交于 2020-02-17 15:30:32
线程同步 如果多个线程共同对某个数据修改,则可能出现不可预料的结果,为了保证数据的正确性,需要对多个线程进行同步。 使用 Thread 对象的 Lock 和 Rlock 可以实现简单的线程同步,这两个对象都有 acquire 方法和 release 方法,对于那些需要每次只允许一个线程操作的数据,可以将其操作放到 acquire 和 release 方法之间。如下: 多线程的优势在于可以同时运行多个任务(至少感觉起来是这样)。但是当线程需要共享数据时,可能存在数据不同步的问题。 考虑这样一种情况:一个列表里所有元素都是0,线程"set"从后向前把所有元素改成1,而线程"print"负责从前往后读取列表并打印。 那么,可能线程"set"开始改的时候,线程"print"便来打印列表了,输出就成了一半0一半1,这就是数据的不同步。为了避免这种情况,引入了锁的概念。 锁有两种状态——锁定和未锁定。每当一个线程比如"set"要访问共享数据时,必须先获得锁定;如果已经有别的线程比如"print"获得锁定了,那么就让线程"set"暂停,也就是同步阻塞;等到线程"print"访问完毕,释放锁以后,再让线程"set"继续。 经过这样的处理,打印列表时要么全部输出0,要么全部输出1,不会再出现一半0一半1的尴尬场面。 实例: #!/usr/bin/python3 import time import

Python3 多线程

北战南征 提交于 2020-02-17 15:30:09
多线程类似于同时执行多个不同程序,多线程运行有如下优点: 使用线程可以把占据长时间的程序中的任务放到后台去处理。 用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度 程序的运行速度可能加快 在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了。在这种情况下我们可以释放一些珍贵的资源如内存占用等等。 线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。 每个线程都有他自己的一组CPU寄存器,称为线程的上下文,该上下文反映了线程上次运行该线程的CPU寄存器的状态。 指令指针和堆栈指针寄存器是线程上下文中两个最重要的寄存器,线程总是在进程得到上下文中运行的,这些地址都用于标志拥有线程的进程地址空间中的内存。 线程可以被抢占(中断)。 在其他线程正在运行时,线程可以暂时搁置(也称为睡眠) -- 这就是线程的退让。 线程可以分为: 内核线程: 由操作系统内核创建和撤销。 用户线程: 不需要内核支持而在用户程序中实现的线程。 Python3 线程中常用的两个模块为: _thread threading(推荐使用) thread 模块已被废弃。用户可以使用 threading 模块代替。所以,在

python多线程

蓝咒 提交于 2020-02-17 15:29:49
一、多线程类似于同时执行多个不同程序,多线程运行有如下优点:   1.使用线程可以把耗时任务放到后台去处理。   2.用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度   3.程序的运行速度可能加快   4.在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了。在这种情况下我们可以释放一些珍贵的资源如内存占用等等。 二、多线程的特点   线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。   线程可以被抢占(中断)。   在其他线程正在运行时,线程可以暂时搁置(也称为睡眠) -- 这就是线程的退让。 三、线程的创建 python实现多线程有两种方式(函数,用类来包装线程对象) 1、函数式:调用thread模块中的start_new_thread()函数来产生新线程 import timeimport _threaddef func(thread,delay): for x in range(5): time.sleep(delay) print("%d正在执行线程%s"%(x,thread)) if x==4: _thread.exit()try: _thread.start_new_thread(func, ("thread_1",2) ) _thread.start_new

并发函数--线程

自古美人都是妖i 提交于 2020-02-17 14:47:29
计算机的执行单位以线程为单位.计算机的最小可执行单位是线程. 进程是资源分配的基本单位,线程是可执行的基本单位.是可被调度的基本单位. 线程不可以自己独立拥有资源,线程的执行必须依赖于所属进程的资源. 线程被称作轻量级的进程.线程的切换速度不进程块. 进程中必须至少要有一个线程 GIL:全局解释锁,用来锁解释器(只有CPython解释器才有),限制只能有一个线程来访问CPU.对于线程来说,因为有了GIL所以只有并发没有并行,CPU允许一个线程执行5毫秒 线程又分为:      用户级线程:对于程序员来说的.这样的线程完全被程序员控制执行调度      内核级线程:对于计算机内核来说的,这样的线程完全被内核控制调度 线程的模块:threading 线程是由:代码块,数据段,TCB(线程控制块)组成. 实现线程的两种方法: 1.直接实现 例: from threading import Threaddef func(i): print(i+1)for i in range(100): t = Thread(target = func,args = (i,)) #开启100个线程 t.start() 2.继承Thread类 例: from threading import Threadclass Mythread(Thread): #继承Thread类来开启线程 def __init__

python多线程

你。 提交于 2020-02-15 08:56:10
python多线程 文章目录 python多线程 初始案例 主线程何时结束 join()阻塞 共享变量 锁 初始案例 import threading import time def listen_music ( name ) : while True : time . sleep ( 1 ) print ( name , "正在播放音乐" ) def download_music ( name ) : while True : time . sleep ( 2 ) print ( name , "正在下载音乐" ) if __name__ == '__main__' : p1 = threading . Thread ( target = listen_music , args = ( "网易云音乐" , ) ) p2 = threading . Thread ( target = download_music , args = ( "网易云音乐" , ) ) p1 . start ( ) p2 . start ( ) 观察上面的输出代码可以知道: 1.CPU是按照时间片轮询的方式来执行子线程的。cpu内部会合理分配时间片。时间片到a程序的时候,a程序如果在休眠,就会自动切换到b程序。 2.严谨来说,CPU在某个时间点,只在执行一个任务,但是由于CPU运行速度和切换速度快

复习打卡--0826协程、进程池、线程/进程/协程对比

喜夏-厌秋 提交于 2020-02-14 02:17:53
一、协程 协程,又称微线程 协程是python中另外一种实现多任务的方式,只不过比线程更小,占用更小执行单元(理解为需要的资源) 它自带CPU上下文,这样只要在合适的时间,我们就可以把一个协程切换到另一个协程,只要这个过程保存或恢复CPU上下文那么程序还是可以运行的   通俗的理解 在一个线程中的某个函数,可以在任何地方保存当前函数的一些临时变量等信息,然后切换到另外一个函数中执行,注意不是通过调用函数的方式做到的,并且切换的次数以及什么时候再切换到原来的函数都由开发者自己决定   协程和线程差异 在实现多任务时,线程切换从系统层面远不止保存和恢复CPU上下文这么简单,操作系统为了程序的高效性每个线程都有自己缓存Cache等等数据,操作系统还会帮你做这些数据的恢复操作。所以线程的切换比较耗性能。但是协程的切换之间单纯的操作CPU的上下文,所以一秒钟切换个上百万次性能都扛得住。 # 协程的实现: 通过含yield关键字的生成器函数来实现协程 def work1(): for i in range(10): print('---work1获取数据{}'.format(i)) yield i def work2(): for i in range(10) : print('---work2获取数据{}'.format(i)) yield i def main(): g1=work1()

复习打卡--0823 队列和多进程

北城以北 提交于 2020-02-13 02:33:44
一、队列 Python的Queue模块中提供了同步的、线程安全的队列类,包括 FIFO (先入先出)队列 Queue , LIFO (后入先出)队列 LifoQueue ,和优先级队列 PriorityQueue 。这些队列都实现了锁原语,能够在多线程中直接使用。可以使用队列来实现线程间的同步。 queue.Queue(maxsize=0) maxsize默认为0,不设置或设置为负数时,表示可接受的消息数量没有上限。 常用方法: Queue.task_done() 在完成一项工作之后,Queue.task_done()函数向任务已经完成的队列发送一个信号。每个get()调用得到一个任务,接下来task_done()调用告诉队列该任务已经处理完毕。 Queue.join() 实际上意味着等到队列为空,再执行别的操作 Queue.put(item,block=True, timeout=None) 写入队列,block=True,Timeout=3 意味着等待3s,队列仍没有位置就报错;block=False 意思是不等待,队列如果满了直接报错; Queue.get(block=True, timeout=None) 获取队列,block和timeout参数说明同上put Queue.get_nowait() 相当于Queue.get(block=False),不等待 Queue