一、线程

1.线程

  1)、什么是线程

    线程是cpu调度的最小单位

    线程是进程的必要组成单位

      一个进程里至少含有一个线程

  2)、主线程

     程序开始运行的视乎,就产生了一个主线程来运行这个程序

  3)、子线程

    是由主线程开启的其他线程

  4)、各线程之间的工作

    异步的

    数据共享的

  5)、GIL Cpython全局解释器锁

    Cpython解释器,在同一个进程中的多个线程,每次只能有一个线程可以获得执行CPU的权限。

    这是由于Cpython的垃圾回收线程等原因导致

2.线程的开启

  #  线程不能在外界的干扰下结束,而是等待程序的执行完毕才结束,主线程要等待子线程的结束而结束。

  

from threading import  Thread,currentThread

def t_func():
global n
n -= 1
print(currentThread()) if __name__ == '__main__':
n = 100
t_lst = []
for i in range(100):
t = Thread(target=t_func)
t.start()
t_lst.append(t)
print(t.ident,t.name,t.is_alive())
for t in t_lst:t.join()
print(n)

3.守护线程

  # 守护线程,会等待主线程执行完毕才结束,主线程会等待所有子线程结束而结束。

  

from threading import Thread,currentThread,active_count,enumerate
import time def func1():
time.sleep(3)
print('in func1')
def func2():
while True:
time.sleep(0.5)
print('in func2') if __name__ == '__main__':
Thread(target=func1).start()
t = Thread(target=func2, daemon=True)
# t.setDaemon(True)
# t.daemon = True
t.start()
# print(enumerate())
# print(active_count())
# print(currentThread())
# print(t.getName())
# print(t.setName('zzz'))
# print(t.getName())
print('主线程') # 守护线程:会等待主线程执行完毕而结束,主线程会等待所有子进程结束后才结束

守护进程

4.锁

  区别GIL和锁,GIL只是同进程中的不同线程只能有一个线程访问CPU,而互斥锁,是保障数据安全的一种机制,二者不冲突。

  

from threading import Lock,RLock,Thread

# 数据不安全实例,由于global数据共享,导致两个线程可能仅计算完+8,还未写入,就被另一个线程抢到执行
# 权限被赋值为0
# def change_balance(n):
# global balance
# balance += n
# balance -= n
#
#
# def run_thread(n):
# for i in range(150000):
# change_balance(n)
#
#
# balance = 0
# t1 = Thread(target=run_thread, args=(5,))
# t2 = Thread(target=run_thread, args=(8,))
# t1.start()
# t2.start()
# t1.join()
# t2.join()
# print(balance) # 加锁 保障数据安全 def change_balance(n):
global balance
balance += n
balance -= n def run_thread(n):
for i in range(150000):
with lock:change_balance(n) balance = 0
lock = Lock()
t1 = Thread(target=run_thread, args=(5,))
t2 = Thread(target=run_thread, args=(8,))
t1.start()
t2.start()
t1.join()
t2.join()
print(balance)

数据安全加锁

5.死锁和递归锁

  互斥锁和递归锁的区别:

    #互斥锁在同一个线程中连续acquire一次以上就会死锁

    #递归锁在同一个线程中可以连续的acquire多次而不发生死锁

  #普遍:递归锁可以代替互斥锁来解决死锁现象

  #实际上:递归锁的解决死锁实际上是牺牲了时间和空间的

    # 死锁从本质上来说是一种逻辑错误

    # 递归锁没有从根本上解决死锁问题

  递归锁画图描述:

  

from threading import Lock
# 互斥锁
# lock = Lock()
# lock.acquire()
# print(123)
# lock.release() from threading import RLock
# 递归锁
# lock = RLock()
# lock.acquire()
# lock.acquire()
# print(123)
# lock.release() # 死锁
# 科学家吃面问题
# import time
# from threading import Thread,Lock
#
# def eat1(name,fork_lock,noodle_lock):
# fork_lock.acquire()
# print('%s拿到叉子了'%name)
# noodle_lock.acquire()
# print('%s拿到面条了' % name)
# print('%s吃面'%name)
# noodle_lock.release()
# fork_lock.release()
#
# def eat2(name,fork_lock,noodle_lock):
# noodle_lock.acquire()
# print('%s拿到面条了' % name)
# time.sleep(1)
# fork_lock.acquire()
# print('%s拿到叉子了' % name)
# print('%s吃面'%name)
# fork_lock.release()
# noodle_lock.release()
#
# fork_lock = Lock()
# noodle_lock = Lock()
# Thread(target=eat1,args=('alex',fork_lock,noodle_lock)).start()
# Thread(target=eat2,args=('wusir',fork_lock,noodle_lock)).start()
# Thread(target=eat1,args=('yuan',fork_lock,noodle_lock)).start()
# Thread(target=eat2,args=('jin',fork_lock,noodle_lock)).start() # 递归锁解决死锁现象
# import time
# from threading import Thread,RLock
#
# def eat1(name,fork_lock,noodle_lock):
# fork_lock.acquire()
# print('%s拿到叉子了'%name)
# noodle_lock.acquire()
# print('%s拿到面条了' % name)
# print('%s吃面'%name)
# noodle_lock.release()
# fork_lock.release()
#
# def eat2(name,fork_lock,noodle_lock):
# noodle_lock.acquire()
# print('%s拿到面条了' % name)
# time.sleep(1)
# fork_lock.acquire()
# print('%s拿到叉子了' % name)
# print('%s吃面'%name)
# fork_lock.release()
# noodle_lock.release()
#
# noodle_lock = fork_lock = RLock()
# Thread(target=eat1,args=('alex',fork_lock,noodle_lock)).start()
# Thread(target=eat2,args=('wusir',fork_lock,noodle_lock)).start()
# Thread(target=eat1,args=('yuan',fork_lock,noodle_lock)).start()
# Thread(target=eat2,args=('jin',fork_lock,noodle_lock)).start() # import time
# from threading import Thread,RLock
#
# def eat1(name,lock):
# lock.acquire()
# print('%s拿到叉子了'%name)
# print('%s拿到面条了' % name)
# print('%s吃面'%name)
# lock.release()
#
# def eat2(name,lock):
# lock.acquire()
# print('%s拿到面条了' % name)
# time.sleep(1)
# print('%s拿到叉子了' % name)
# print('%s吃面'%name)
# lock.release()
#
# noodle_fork_lock = Lock()
# Thread(target=eat1,args=('alex',noodle_fork_lock)).start()
# Thread(target=eat2,args=('wusir',noodle_fork_lock)).start()
# Thread(target=eat1,args=('yuan',noodle_fork_lock)).start()
# Thread(target=eat2,args=('jin',noodle_fork_lock)).start() # 互斥锁和递归锁的区别 *****
# 互斥锁在同一个线程中连续acquire一次以上就会死锁
# 递归锁在同一个线程中可以连续的acquire多次而不发生死锁
# 普遍 :递归锁可以代替互斥锁来解决死锁现象 # 实际上 : 递归锁的解决死锁实际上是牺牲了时间和空间的 ****
# 死锁从本质上来讲是一种逻辑错误
# 递归锁没有从根本上解决死锁问题

6.事件

event.isSet():返回event的状态值;
event.wait():如果 event.isSet()==False将阻塞线程;
event.set(): 设置event的状态值为True,所有阻塞池的线程激活进入就绪状态, 等待操作系统调度;
event.clear():恢复event的状态值为False。
from threading import Thread,Event,currentThread
import time,random def check_mysql():
print('\033[45m[%s]正在检查mysql' % currentThread().getName())
time.sleep(random.randint(0,2))
event.set() def conn_mysql():
count = 1
while not event.is_set():
if count > 3:
raise TimeoutError('链接超时')
print('%s第%s次尝试链接' %(currentThread().getName(),count))
time.sleep(0.5)
count += 1
print('<%s>连接成功' % currentThread().getName()) if __name__ == '__main__':
event = Event()
check = Thread(target=check_mysql)
conn1 = Thread(target=conn_mysql)
conn2 = Thread(target=conn_mysql)
check.start()
conn1.start()
conn2.start()

模拟检查连接mysql的例子

7.定时器

# 可以定时多少时间后开始执行线程中的任务。

from threading import Timer,Thread,currentThread

def func(n):
print('in func', currentThread().getName(),'args%s'%n) t = Timer(3,func,args=(1,))
t.start()
print(currentThread().getName())
from threading import Timer,Thread,currentThread
import time def func(n):
print('in func', currentThread().getName(),'args%s'%n) t = Timer(3,func,args=(1,))
t.start()
time.sleep(1)
print(t.is_alive())
print(currentThread().getName())

定时器的例子

8.条件

# 一次放行多少个线程,放完就没有了,顺序通过,

# 在acquire()和release必须一一对应,wait或notify之前必须有acquire()

from threading import Condition,Thread

def func(n):
con.acquire()
con.wait()
print('run the thread %s' % n)
con.release() if __name__ == '__main__':
con = Condition()
for i in range(10):
t = Thread(target=func,args=(i,))
t.start() while True:
inp = input('>>>')
if inp == 'q':
break
con.acquire()
con.notify(int(inp))
con.release()

      

9.队列(和threading模块没关系了)

  Queue(),PriorityQueue(),LifoQueue()

  

import queue
# q = queue.Queue() # 先进先出队列,维护先进先出顺序
# q.put(2)
# q.put(3)
# q.put(4)
# print(q.get())
# print(q.get())
# print(q.get()) # q = queue.LifoQueue() # 后进先出队列,栈
# q.put(2)
# q.put(3)
# q.put(4)
# print(q.get())
# print(q.get())
# print(q.get()) q = queue.PriorityQueue() # 优先级队列,优先级相同,根据ascii码先后 q.put((10, 2))
q.put((20, 3))
q.put((1, 4))
q.put((100, 'b'))
q.put((100, 'a')) print(q.get())
print(q.get())
print(q.get())
print(q.get())
print(q.get())

三种队列举例

10.池

  multiprocessing中的Pool:

    # apply_async 异步提交任务

    # 必须close join之后才能维护主进程和进程池之间的同步

    # map自带close、join效果

    # 获取执行结果get

    # 回调函数 指定callback参数,由主进程执行

concurrent.futures.ThreadPoolExecutor/concurrent.futures.ProcessPoolExecutor

    # submit 异步提交任务

    # 使用shutdown来维护主进程和进程池之间的同步

    # map是不自带shutdown

    # 获取执行结果用result

    # 回调函数 直接调用add_done_callback方法,由子线程/子进程执行

  # 用concurrent.futures,可以轻松的在进程和线程之间切换(代码改个名字即可)

  #并发程序,线程池进程池都要用,只需要导入一个模块

  # concurrent.futures模块是一个新的模块,同意了线程池和进程池的使用方式,对一些操作进行了更合理的规划。

二、协程

    1)、协程--纤程,本质是线程的一部分

    2)、对比线程和协程

      #  线程,正常的线程,遇到阻塞就停下来,直到阻塞事件结束,才继续执行

      #  协程,利用了协程,就把线程分成了好几段,在一个任务出现阻塞的时候,自动切换到另一任务去执行,这些事情在一个线程里面完成。

    3)、如果这个程序从头到尾没有IO,没有阻塞,程序根本就不会在多个任务之间切换,就是一个顺序执行的协程,对于高计算型的代码没有用。

    4)、协程

        # 数据安全的问题不存在了

        # 如何调度的呢?

          # 操作系统不调度协程

          # 用户级别来调度的gevent

          # 协程的调度速度比线程还快

          # 协程的调度由于是python代码级别而不是操作系统级别,所有用户的可控性更强,降低了操作系统的工作量。

      5)、协程到底是怎么实现程序之间的切换的

      生成器:

      

def func():
print(123)
yield 1
print(456)
yield 2
print(789)
yield 3 def wahaha(g):
for i in g:
print(i) g = func()
wahaha(g)

生成器程序之间切换的例子

协程之间的切换:gevent依赖greenlet,协程之间的切换有greenlet完成

      

# def func():
# print(123)
# yield 1
# print(456)
# yield 2
# print(789)
# yield 3
#
#
# def wahaha(g):
# for i in g:
# print(i)
#
# g = func()
# wahaha(g) # 协程之间的切换 from greenlet import greenlet def eat(name):
print('%s eat 1' %name)
g2.switch('egon')
print('%s eat 2' %name)
g2.switch()
def play(name):
print('%s play 1' %name)
g1.switch()
print('%s play 2' %name) g1 = greenlet(eat)
g2 = greenlet(play) g1.switch('alex')

greenlet

from gevent import monkey
monkey.patch_all()
import time
import gevent # 能够在遇到自己认识的IO操作的时候主动调用greenlet中的switch来切换到其他的任务以提高程序的效率
from threading import currentThread
def eat(name):
print(currentThread())
print('%s eat 1' %name)
time.sleep(2)
print('%s eat 2' %name) def play(name):
print(currentThread())
print('%s play 1' %name)
time.sleep(1)
print('%s play 2' %name) g1=gevent.spawn(eat,'egon') # 就是发布了任务
g2=gevent.spawn(play,name='egon') # 就是发布了任务
# g1.join() # 等待g1任务执行完毕,阻塞,帮助你完成g1中函数的全部内容
# g2.join()
gevent.joinall([g1,g2])
print('主')

gevent

# 效率对比

from gevent import spawn, joinall, monkey;
monkey.patch_all() import time def task(pid):
time.sleep(0.5)
print('Task %s done' % pid) def synchronous(): # 同步
for i in range(10):
task(i) def asynchronous(): # 异步
# g_l = []
# for i in range(10):
# g = spawn(task,i)
# g_l.append(g)
# for g in g_l:g.join()
# joinall(g_l) joinall([spawn(task, i) for i in range(10)]) if __name__ == '__main__':
# print('Synchronous:')
# synchronous()
print('Asynchronous:')
asynchronous()

高IO同步异步效率对比

  
# 解决并发问题???
# 多进程  高计算型,浪费操作系统和资源,可以利用多核
# 多线程  高IO型,也会给操作系统添加负担,会占用比进程少的资源,
          # 受到GIL,不能利用多核
# 协程    高IO型,完全不会给操作系统添加负担,几乎不占资源
          # 始终不能利用多核

# 多进程 + 多线程  = 100
# 多进程 + 多线程 + 协程  = 50000/4c
    # 4c
    # 多进程 CPU+1  = 5
    # 多线程 CPU*5  = 20
    # 协程   500个协程

       

    

python全栈开发day35-线程、协程的更多相关文章

  1. Python全栈开发:线程、进程和协程

    Python线程 Threading用于提供线程相关的操作,线程是应用程序中工作的最小单元. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 #!/usr/bin/env pytho ...

  2. Python全栈开发:线程代码实例

    #进程与线程的关系 """ 多进程(主进程,子进程): 优点:能同时利用多个CPU,进行多个操作,提高效率. 缺点:耗费内存资源(进程要开辟内存空间),进程不是越多越好, ...

  3. python全栈开发目录

    python全栈开发目录 Linux系列 python基础 前端~HTML~CSS~JavaScript~JQuery~Vue web框架们~Django~Flask~Tornado 数据库们~MyS ...

  4. Python全栈开发【面向对象】

    Python全栈开发[面向对象] 本节内容: 三大编程范式 面向对象设计与面向对象编程 类和对象 静态属性.类方法.静态方法 类组合 继承 多态 封装 三大编程范式 三大编程范式: 1.面向过程编程 ...

  5. Python全栈开发【模块】

    Python全栈开发[模块] 本节内容: 模块介绍 time random os sys json & picle shelve XML hashlib ConfigParser loggin ...

  6. python全栈开发中级班全程笔记(第二模块、第四章)(常用模块导入)

    python全栈开发笔记第二模块 第四章 :常用模块(第二部分)     一.os 模块的 详解 1.os.getcwd()    :得到当前工作目录,即当前python解释器所在目录路径 impor ...

  7. python全栈开发学习_内容目录及链接

    python全栈开发学习_day1_计算机五大组成部分及操作系统 python全栈开发学习_day2_语言种类及变量 python全栈开发_day3_数据类型,输入输出及运算符 python全栈开发_ ...

  8. Python 全栈开发【第0篇】:目录

    Python 全栈开发[第0篇]:目录   第一阶段:Python 开发入门 Python 全栈开发[第一篇]:计算机原理&Linux系统入门 Python 全栈开发[第二篇]:Python基 ...

  9. Python全栈开发【面向对象进阶】

    Python全栈开发[面向对象进阶] 本节内容: isinstance(obj,cls)和issubclass(sub,super) 反射 __setattr__,__delattr__,__geta ...

  10. Python全栈开发【基础四】

    Python全栈开发[基础四] 本节内容: 匿名函数(lambda) 函数式编程(map,filter,reduce) 文件处理 迭代器 三元表达式 列表解析与生成器表达式 生成器 匿名函数 lamb ...

随机推荐

  1. 个股和股票池的beta系数的估算

    个股的beta系数的估算 代码 def test_gg_beta(symbol='000895.sz', start='2018-01-01', plot_price=True, align_to=' ...

  2. 词典的实现(1)--Map的底层实现

    1,词典是这样的一种数据结构:它能根据给定的键(索引值,key)来查找其对应的值(value)是否存在,在JAVA中主要由java.util.HashMap来完成该功能.如电话本就是词典的一个具体实例 ...

  3. flash GC

    所有应用程序都要管理内存.应用程序的内存管理包括用于确定何时分配内存,分配多少内存,何时将内容放入回收站,以及何时清空回收站的准则.MMgc是 Flash Player用于几乎所有内存分配工作的通用内 ...

  4. mysql 原理 ~ 事务隔离机制

    简介: 事务隔离知多少内容  一 基础知识  1 事务特性 ACID   A 原子性 C 一致性 I 隔离性 D 持久性  2 并行事务出现的问题    1 脏读 读取了其他事务未提交的数据      ...

  5. ROS 时间同步问题

    0. 问题 两台ubuntu主机无法与一台debian主机使用分布式通信,摄像头发出的话题机器人收不到,考虑是时间同步的问题. 也可能是系统不统一的问题; 今天在家实验了一下,时间差6min,照样可以 ...

  6. [Shell]获取IP地址

    ifconfig eth0 | grep "inet addr:" | awk '{print $2}' | cut -c 6- ifconfig eth1 | grep &quo ...

  7. mysql系列十一、mysql优化笔记:表设计、sql优化、配置优化

    可以从这些方面进行优化: 数据库(表)设计合理 SQL语句优化 数据库配置优化 系统层.硬件层优化 数据库设计 关系数据库三范式 1NF:字段不可分; 2NF:有主键,非主键字段依赖主键; 3NF:非 ...

  8. git强制覆盖更新

    1.选择项目,右键选择Team,选择Team里面的Reset. 2.点击Reset后弹出Reset窗口,选择Hard选项,这样就会把远端的项目完全拉下来覆盖本地,本地没有的文件也会被创建,点击确定.

  9. Vue.js——component(组件)

    概念: 组件(Component)是自定义元素. 作用: 可以扩展HTML元素,封装可重用的代码. <div id="myView"> <!-- 把学生的数据循环 ...

  10. html的结构-厂子型的布局

    上图所示的布局设计是很常见的.这个该怎么做呢? 技术需求:header 要固定住在顶部,不随鼠标滚动而向上移动:左边的div的有一定的宽度,但是要贴浏览器的底部(屏幕顶部):右边的dv要占据右边的全屏 ...