线程:
  优点:共享内存,IO操作时,创造并发操作
  缺点:枪战资源
  线程不是越多越好,具体案例具体分析,请求上下文切换耗时
  IO密集型适用于线程,IO操作打开文件网络通讯类,不需要占用CPU,只是由CPU调度一下(不占用CPU)

自定义进程和线程:注意python解释器自带了主进程和主线程,比如在代码文件里没有定义线程和进程,程序也能运行就是靠的解释器自带主进程的主线程执行的

  自定义进程:
    由主进程创建,子进程
  自定义线程:
    由主线程创建,子线程

GIL全局解释器锁:

GIL全局解释器锁在进程入口,控制着进程数量与CPU的相应

threading线程模块

线程是应用程序中工作的最小单元

threading 模块建立在 _thread 模块之上。thread 模块以低级、原始的方式来处理和控制线程,而 threading 模块通过对 thread 进行二次封装,提供了更方便的 api 来处理线程。

hread()创建线程对象【有参】

使用方法:赋值变量 = 模块名称.Thread(target=事件函数,args=元祖类型事件函数的实际参数)  如函数多个参数,元祖里就是多个元素

格式:t = threading.Thread(target=show, args=(i,))

currentThread()获取当前线程【无参】

使用方法:自定义变量 = threading模块名称.currentThread()

格式:current_thread = threading.currentThread()

start()激活线程【无参】

使用方法:thread对象变量.start()

格式:t.start()

  1. #!/usr/bin/env python
  2. # -*- coding:utf8 -*-
  3. import threading #导入线程模块
  4. import time #导入时间模块
  5. def show(arg): #定义函数
  6. time.sleep(3) #睡眠3秒
  7. print('线程'+str(arg)) #打印线程加循环次数
  8. for i in range(10): #定义一个10次循环
  9. t = threading.Thread(target=show, args=(i,)) #用threading模块的Thread类来创建子线程对象
  10. t.start() #激活子线程
  11. print("默认主线程等待子线程完成任务后,主线程停止")
  12. # 输出
  13. # 默认主线程等待子线程完成任务后,主线程停止
  14. # 线程0
  15. # 线程5
  16. # 线程8
  17. # 线程3
  18. # 线程6
  19. # 线程4
  20. # 线程1
  21. # 线程7
  22. # 线程2
  23. # 线程9

上述代码创建了10个“前台”线程,然后控制器就交给了CPU,CPU根据指定算法进行调度,分片执行指令。

  1. from threading import Thread
  2. import time
  3. class Sayhi(Thread):
  4. def __init__(self,name):
  5. super().__init__()
  6. self.name=name
  7. def run(self):
  8. time.sleep(2)
  9. print('%s say hello' % self.name)
  10.  
  11. if __name__ == '__main__':
  12. t = Sayhi('egon')
  13. t.start()
  14. print('主线程')

在一个进程下开启多个线程与在一个进程下开启多个子进程的区别

  1. from threading import Thread
  2. from multiprocessing import Process
  3. import os
  4.  
  5. def work():
  6. print('hello')
  7.  
  8. if __name__ == '__main__':
  9. #在主进程下开启线程
  10. t=Thread(target=work)
  11. t.start()
  12. print('主线程/主进程')
  13. '''
  14. 打印结果:
  15. hello
  16. 主线程/主进程
  17. '''
  18.  
  19. #在主进程下开启子进程
  20. t=Process(target=work)
  21. t.start()
  22. print('主线程/主进程')
  23. '''
  24. 打印结果:
  25. 主线程/主进程
  26. hello
  27. '''

线程的join与setdaemon

与进程的方法都是类似的,其实是multiprocessing模仿threading的接口

join与setdaemon

join()逐个执行每个线程,等待一个线程执行完毕后继续往下执行,该方法使得多线程变得无意义【有参可选】

有参可选,参数为等待时间,秒为单位,如t.join(1) 就是一个线程不在是等待它执行完,而是只等待它1秒后继续下一个线程

  1. from threading import Thread
  2. import time
  3. def sayhi(name):
  4. time.sleep(2)
  5. print('%s say hello' %name)
  6.  
  7. if __name__ == '__main__':
  8. t=Thread(target=sayhi,args=('egon',))
  9. t.setDaemon(True) #等待子线程完成
  10. t.start()
  11. t.join()
  12. print('主线程')
  13. print(t.is_alive())
  1. Thread实例对象的方法
    # isAlive(): 返回线程是否活动的。

  isAlive()判断线程是否为激活状态返回布尔值【无参】

  使用方法:thread对象变量.isAlive()

  格式:t.isAlive()

  1.  # getName(): 返回线程名。
  1. getName()获取线程的名称【无参】
  1.  使用方法:thread对象变量.getName()
     格式:t.getName()
  1. # setName(): 设置线程名。

  setName()设置线程的名称【有参】

  使用方法:thread对象变量.setName("要设置的线程名称")

  格式:t.setName("jhf")

  name获取或设置线程的名称【无参】

  使用方法:thread对象变量.name

  格式:t.name

  

  isDaemon()判断是否为守护线程,也就是主线程是否等待子线程执行完成后,才停止主线程,返回布尔值【无参】

  使用方法:thread对象变量.isDaemon()

  格式:t.isDaemon()

  1. threading模块提供的一些方法:
  2. # threading.currentThread(): 返回当前的线程变量。
  3. # threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
  4. # threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。

线程锁threading.RLock和threading.Lock

我们使用线程对数据进行操作的时候,如果多个线程同时修改某个数据,可能会出现不可预料的结果,为了保证数据的准确性,引入了锁的概念。

没有线程锁的情况列如:一个全局变量值为50,创建10条线程让每条线程累计减一,输出的结果是10个40,原因是10条线程同时减一就减去了10,所以打印出来就是10个40了

未使用锁:

  1. #!/usr/bin/env python
  2. # -*- coding:utf8 -*-
  3. import threading #导入线程模块
  4. import time #导入时间模块
  5. globals_num = 50 #设置一个变量
  6. def Func(a): #定义一个函数
  7. global globals_num #将变量转换成全局变量,函数里可以调用
  8. globals_num -= 1 #全局变量减1
  9. time.sleep(1) #睡眠1秒
  10. print(globals_num,a) #打印全局变量减少后的结果,和函数传进来的值
  11. for i in range(10): #创建一个10次循环
  12. t = threading.Thread(target=Func,args=(i,)) #创建线程对象
  13. t.start() #激活线程
  14. # 输出 没有线程锁,线程之间抢占了数据资源
  15. # 40 5
  16. # 40 3
  17. # 40 6
  18. # 40 4
  19. # 40 0
  20. # 40 2
  21. # 40 1
  22. # 40 9
  23. # 40 8
  24. # 40 7
  1. 根据上列情况可以看出,没有线程锁,线程之间抢占了数据资源
  1. 线程锁就是将线程锁定,一个线程执行完毕后释放锁后在执行第二个线程
  2. RLock()定义线程锁对象

使用方法:定义对象变量 = threading模块名称.RLock()

格式:lock = threading.RLock()

acquire()获得锁,将线程锁定,一个线程执行完毕释放锁后在执行第二个线程

使用方法:线程锁对象变量.acquire()

格式:lock.acquire()

release()释放线程锁

使用方法:线程锁对象变量.release()

格式:lock.release()

使用锁:

  1. #!/usr/bin/env python
  2. # -*- coding:utf8 -*-
  3. import threading #导入线程模块
  4. import time #导入时间模块
  5. globals_num = 50 #设置一个变量
  6. lock = threading.RLock()
  7. def Func(a): #定义一个函数
  8.  
  9. lock.acquire() # 获得锁,将线程锁定,一个线程执行完毕后在执行第二个线程
  10.  
  11. global globals_num #将变量转换成全局变量,函数里可以调用
  12. globals_num -= 1 #全局变量减1
  13. time.sleep(1) #睡眠1秒
  14. print(globals_num,a) #打印全局变量减少后的结果,和函数传进来的值
  15.  
  16. lock.release() # 释放锁
  17.  
  18. for i in range(10): #创建一个10次循环
  19. t = threading.Thread(target=Func,args=(i,)) #创建线程对象
  20. t.start() #激活线程
  21. # 输出 将线程锁定,一个线程执行完毕后在执行第二个线程
  22. # 49 0
  23. # 48 1
  24. # 47 2
  25. # 46 3
  26. # 45 4
  27. # 44 5
  28. # 43 6
  29. # 42 7
  30. # 41 8
  31. # 40 9

threading.RLock和threading.Lock 的区别

RLock允许在同一线程中被多次acquire。而Lock却不允许这种情况。 如果使用RLock,那么acquire和release必须成对出现,即调用了n次acquire,必须调用n次的release才能真正释放所占用的琐。

threading.Event事件对象

Event()创建标识事件对象,全局定义了一个“Flag”,如果“Flag”值为 False,那么当程序执行 event.wait 方法时就会阻塞,如果“Flag”值为True,那么event.wait 方法时便不再阻塞

python线程的事件用于主线程控制其他线程的执行,事件主要提供了三个方法 set、wait、clear。

事件处理的机制:全局定义了一个“Flag”,如果“Flag”值为 False,那么当程序执行 event.wait 方法时就会阻塞,如果“Flag”值为True,那么event.wait 方法时便不再阻塞。

当线程执行的时候,如果flag为False,则线程会阻塞,当flag为True的时候,线程不会阻塞。它提供了本地和远程的并发性。

Event事件对象的方法有

  wait([timeout]) : 堵塞线程,直到Event对象内部标识位被设为True或超时(如果提供了参数timeout)。
  set() :将标识位设为Ture
  clear() : 将标识位设为False。
  isSet() :判断标识位是否为Ture。

  1. #!/usr/bin/env python
  2. # -*- coding:utf8 -*-
  3. import threading
  4. def do(event):
  5. print('start')
  6. event.wait() #堵塞线程,直到Event对象内部标识位被设为True或超时(如果提供了参数timeout)
  7. print('execute')
  8. event_obj = threading.Event() #创建标识事件对象
  9. for i in range(10):
  10. t = threading.Thread(target=do, args=(event_obj,)) #创建线程对象
  11. t.start() #激活线程
  12. event_obj.clear() #将标识设置为False
  13. inp = input('input:')
  14. if inp == 'true':
  15. event_obj.set() #将标识设置为True
  16. # 输出
  17. # start
  18. # start
  19. # start
  20. # start
  21. # start
  22. # start
  23. # start
  24. # start
  25. # start
  26. # input:true
  27. # execute
  28. # execute
  29. # execute
  30. # execute
  31. # execute
  32. # execute
  33. # execute
  34. # execute
  35. # execute
  36. # execute

threading.BoundedSemaphore信号对象

是同时允许一定数量的线程更改数据 ,比如厕所有3个坑,那最多只允许3个人上厕所,后面的人只能等里面有人出来了才能再进去。

 BoundedSemaphore()创建信号对象【有参】

使用方法:定义变量.threading.BoundedSemaphore(最大允许线程数)

格式:semaphore  = threading.BoundedSemaphore(5)

BoundedSemaphore信号对象的方法有

  acquire()获取信号
  release()释放信号

  1. from threading import Thread,Semaphore
    import time
    def work(id):
    with sem:
    time.sleep(2)
    print('%s say hello' %id)
  2.  
  3. if __name__ == '__main__':
    sem=Semaphore(5) #最多以5个线程同时运行
    for i in range(20):
    t=Thread(target=work,args=(i,))
    t.start()

queue模块

Queue 就是对队列,它是线程安全的

举例来说,我们去肯德基吃饭。厨房是给我们做饭的地方,前台负责把厨房做好的饭卖给顾客,顾客则去前台排队领取做好的饭。这里的前台就相当于我们的队列。

这个模型也叫生产者-消费者模型。

Queue()创建队列对象【有参】

使用方法:定义变量 = queue.Queue(对列长度数) 0表示长度无限制

格式:message = queue.Queue(10)

Queue对象方法有:

  join()等到队列为空的时候,在执行别的操作【无参】

  qsize()返回队列的大小(不可靠),因为获取后有可能有新数据加入【无参】

  empty()清空队列里的所有数据

  full()检查队列是否为满,当队列满的时候,返回True,否则返回False(不可靠),因为获取后有可能有新数据加入【无参】

  put(放入对列的数据必选, block=True, timeout=None) 向队列里放入数据(生产)【有参】

    将数据放入对列尾部(生产),数据必须存在,可以参数block默认为True,表示当队列满时,会等待队列给出可用位置,为False时为非阻塞,此时如果队列已满,会引发queue.Full 异常。

    可选参数timeout,表示 会阻塞设置的时间,过后,如果队列无法给出放入item的位置,则引发 queue.Full 异常

  get(block=True, timeout=None)移除并返回队列头部的一个值(消费)【有参】

     可选参数block默认为True,表示获取值的时候,如果队列为空,则阻塞,为False时,不阻塞,若此时队列为空,则引发 queue.Empty异常。

    可选参数timeout,表示会阻塞设置的时候,过后,如果队列为空,则引发Empty异常。

  put_nowait(放入对列的数据必选)向队列里放入数据(生产)【有参】,如果队列满时不阻塞,不等待队列给出可用位置,引发 queue.Full 异常

  get_nowait()移除并返回队列头部的一个值(消费)【无参】,如果队列空时不阻塞,引发 queue.Full 异常

class queue.Queue(maxsize=0) #先进先出

  1. import queue
  2.  
  3. q=queue.Queue()
  4. q.put('first')
  5. q.put('second')
  6. q.put('third')
  7.  
  8. print(q.get())
  9. print(q.get())
  10. print(q.get())
  11. '''
  12. 结果(先进先出):
  13. first
  14. second
  15. third
  16. '''

class queue.LifoQueue(maxsize=0) #last in fisrt out 

  1. import queue
  2.  
  3. q=queue.LifoQueue()
  4. q.put('first')
  5. q.put('second')
  6. q.put('third')
  7.  
  8. print(q.get())
  9. print(q.get())
  10. print(q.get())
  11. '''
  12. 结果(后进先出):
  13. third
  14. second
  15. first
  16. '''

class queue.PriorityQueue(maxsize=0) #存储数据时可设置优先级的队列

  1. import queue
  2.  
  3. q=queue.PriorityQueue()
  4. #put进入一个元组,元组的第一个元素是优先级(通常是数字,也可以是非数字之间的比较),数字越小优先级越高
  5. q.put((20,'a'))
  6. q.put((10,'b'))
  7. q.put((30,'c'))
  8.  
  9. print(q.get())
  10. print(q.get())
  11. print(q.get())
  12. '''
  13. 结果(数字越小优先级越高,优先级高的优先出队):
  14. (10, 'b')
  15. (20, 'a')
  16. (30, 'c')
  17. '''

定时器,指定n秒后执行某操作

  1. from threading import Timer
  2.  
  3. def hello():
  4. print("hello, world")
  5.  
  6. t = Timer(1, hello)
  7. t.start() # after 1 seconds, "hello, world" will be printed
  1.  

Python基础线程和协程的更多相关文章

  1. 11.python之线程,协程,进程,

    一,进程与线程 1.什么是线程 线程是操作系统能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行 ...

  2. python进程.线程和协程的总结

    I.进程: II.多线程threading总结 threading用于提供线程相关的操作,线程是应用系统中工作的最小单位(cpu调用的最小单位). Python当前版本的多线程没有实现优先级,线程组, ...

  3. Python基础篇-day11 - 协程

    本节主要内容: 1.Gevent协程2.Select\Poll\Epoll异步IO与事件驱动3.RabbitMQ队列 1.Gevent协程 1.1协程的好处 无需线程上下文切换的开销无需原子操作锁定及 ...

  4. python简单线程和协程学习

    python中对线程的支持的确不够,不过据说python有足够完备的异步网络框架模块,希望日后能学习到,这里就简单的对python中的线程做个总结 threading库可用来在单独的线程中执行任意的p ...

  5. python中线程 进程 协程

    多线程:#线程的并发是利用cpu上下文的切换(是并发,不是并行)#多线程执行的顺序是无序的#多线程共享全局变量#线程是继承在进程里的,没有进程就没有线程#GIL全局解释器锁#只要在进行耗时的IO操作的 ...

  6. python基础之进程、线程、协程篇

    一.多任务(多线程) 多线程特点:(1)线程的并发是利用cpu上下文的切换(是并发,不是并行)(2)多线程执行的顺序是无序的(3)多线程共享全局变量(4)线程是继承在进程里的,没有进程就没有线程(5) ...

  7. Python进阶(5)_进程与线程之协程、I/O模型

    三.协程 3.1协程概念 协程:又称微线程,纤程.英文名Coroutine.一句话说明什么是线程:协程是一种用户态的轻量级线程. 协程拥有自己的寄存器上下文和栈.协程调度切换时,将寄存器上下文和栈保存 ...

  8. Python学习笔记整理总结【网络编程】【线程/进程/协程/IO多路模型/select/poll/epoll/selector】

    一.socket(单链接) 1.socket:应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socke ...

  9. 图解Python 【第八篇】:网络编程-进程、线程和协程

    本节内容一览图: 本章内容: 同步和异步 线程(线程锁.threading.Event.queue 队列.生产者消费者模型.自定义线程池) 进程(数据共享.进程池) 协程 一.同步和异步 你叫我去吃饭 ...

随机推荐

  1. Win10系列:UWP界面布局基础11

    样式继承 为了使样式便于维护及重复使用,可以在一个样式上引用其他的样式,这就是样式继承.样式继承的方法是:在Style元素的BasedOn属性上使用StaticResource标记扩展来引用被继承的样 ...

  2. learning shell display alert function

    [Purpose]        Shell print function base on err info wrn ext output level   [Eevironment]        U ...

  3. python之路 ---计算机硬件基础

    计算机(computer)俗称电脑,是现代一种用于高速计算的电子计算机器,可以进行数值计算,又可以进行逻辑计算,还具有存储记忆功能.是能够按照程序运行,自动.高速处理海量数据的现代化智能电子设备.一个 ...

  4. Java反射《三》获取属性

    package com.study.reflect; import java.lang.reflect.Field; /** * 反射,获取属性 * @ClassName: FieldDemo * @ ...

  5. bzoj2330

    题解: 差分约束系统 要我们求最小值 显然就是转化为最长路 然后spfa一下即可 代码: #include<bits/stdc++.h> using namespace std; ; lo ...

  6. day056 多表增加和查询

    今日总结: 多表的增删改查操作 多表操作 增 book id title book_detail publish author onetoone manytoone manytomany book_o ...

  7. npm webpack vue-cli

    npm.webpack.vue-cli 快速上手版   Node.js   npm 什么是Node.js  以及npm 简单的来说 Node.js 就是运行在服务端的JavaScript,基于Chro ...

  8. python 正则表达式笔记

    #!usr/bin/env python3 #-*- coding:utf-8 -*- #正则表达式 #在正则表达式中,如果直接给出字符,就是精确匹配.用\d可以匹配一个数字,\w可以匹配一个字母.数 ...

  9. fastIO

    文件系统除了处理正常的IRP 之外,还要处理所谓的FastIo.FastIo是Cache Manager 调用所引发的一种没有irp 的请求.换句话说,除了正常的Dispatch Functions ...

  10. linux一些命令的介绍

    http://www.runoob.com/linux/linux-command-manual.html 寻找文档操作命令wc -l时,发现一个好的介绍linux操作命令的网站.