Python学习之路-随笔03 多线程/进程和协程(上篇)

  

最近东西积攒了太多,感觉再不写进来就要炸了。

1.多线程

1.11 关于多线程的包

相关的python包有几个,比如thread包,到py3改成_thread,而thread有一些问题使得不是很好用。通用的包叫threading。最近都是在用这个。

1.12 threading的使用和常用属性

需要注意的点有生成实例比如t = threading.Thread(target=xxx, args=(xx,)),里面有两个参数,第一个是目标函数,第二个是相关的参数,注意类型。

然后就是start启动,join等待多线程实行完成这两个方法。

#伪代码
t1 = threading.Thread(target=fun1, args=("函数参数 1",))
t1.start()

t2 = threading.Thread(target=fun2, args=("函数参数1", "函数参数2"))
t2.start()

#等待线程
t1.join()
t2.join()

继承threading.Thread使用,需要重写run函数。

class MyThread(threading.Thread):  def __init__(self, arg):    super(MyThread, self).__init__()    self.arg = arg

  def run(self):    time.sleep(2)

其他常用属性和方法有:

threading.currentThread:返回当前线程变量

threading.enumerate:返回一个包含正在运行的线程的list,正在运行的线程指的是线程启动后,结束前的状态

threading.activeCount: 返回正在运行的线程数量,效果跟 len(threading.enumerate)相同

threading.timer: 定时器,利用多线程在指定时间后启动一个功能

thr.setName: 给线程设置名字

thr.getName: 得到线程的名字

守护线程:daemon:即如果将子线程设置成守护线程,则子线程会在主线程结束的时候自动退出,一般认为,守护线程不中要或者不允许离开主线程独立运行

而守护线程能否有效果跟环境相关

t1 = threading.Thread(target=fun, args=() )
# 社会守护线程的方法,必须在start之前设置,否则无效
t1.setDaemon(True)
#t1.daemon = True
t1.start()

1.13 线程相关的问题

因为线程之间有共享状态(资源),会有一些诸如死锁或者同步的问题。解决方法也是大同小异,这些python里都给出了

相应的工具。比如自己设置一个锁/信号灯。用semphore变量,还有可重入锁解锁递归的时候申请锁的问题等等。

线程安全不安全变量list,set,dict,安全变量queue等。

1.14 线程替代方案

替代无非是用进程或者魔改的线程包,诸如subprocess使用进程,multiprocessing用threading派生出来的,使用子进程,可以使用多核或多CPU

还有一个current.future待会儿写

2.多进程

使用的就是上面提到的线程替代方案multiprocessing,方法和threading差不多,multiprocessing.Process(target=xxx, args=(xx,)),然后同样也可以继承后使用,实现方式类似多线程

还有一个就是pid和ppid,即进程ID和父进程ID,还有其他常见的内容比如子进程和父进程共享资源啊,而子线程有自己独立的栈空间啊之类的就不详细描述了

还有其他的诸如生产者-消费者模型,读者-写者模型等等。和上面的一样,也不赘述了,操作系统书里都有,写在这没什么意义。

3.协程

首先来写一下协程的定义:协程是为非抢占式多任务产生子程序的计算机程序组件, 协程允许不同入口点在不同位置暂停或开始执行程序。

在这之前先写两个

3.11 迭代器

有两个概念,一是可迭代对象Iterable,二是迭代器Iterator

Iterable可以用于for循环,二Iterator不仅可以用于for循环还能被next函数调用,可以用isinstance函数判断,比如list是可迭代的。

from collections import Iterable

l = [1,2,3,4]

isinstance(l, Iterable)

out:True

两者之间还可以通过iter函数转换

from collections import Iterator

isinstance(iter(‘abc‘), Iterator)

out:True

3.12 生成器

比如最常见的生成器有L = [x * x for x in range(10)],g = (x * x for x in range(10))这些生成列表,元组的方法

本质是一个函数/方法,每次调用next的时候计算下一个值,最后会抛出StopIteration异常。

函数中包含yield,则叫generator

next调用,遇到yield返回

# 在函数odd中,yield负责返回
def odd():
    print("Step 1")
    yield 1
    print("Step 2")
    yield 2
    print("Step 3")
    yield 3

# odd() 是调用生成器
g = odd()
one = next(g)
print(one)

two = next(g)
print(two)

three = next(g)
print(three)

out:Step 1

  1

  Step 2

  2

  Step 3

  3

3.13 协程

是的,协程和生成器很像,使用yield和send。目的是合理调用各种系统资源和进行协同工作。协程之间切换耗费也很低

协程有四个状态:

GEN_CREATED:等待开始执行

GEN_RUNNING:解释器正在执行

GEN_SUSPENED:在yield表达式处暂停

GEN_CLOSED:执行结束

def simple_coroutine(a):
    print(‘-> start‘) 

    b = yield a # 把A丢出来给aa
    print(‘-> recived‘, a, b)

    c = yield a + b
    print(‘-> recived‘, a, b, c)

# runc
sc = simple_coroutine(5)

aa = next(sc) # 预激,准备好执行协程,程序走到yield停下
print(aa)
bb = sc.send(6) # 5 ,6  把参数6发给b
print(bb)
cc = sc.send(7) # 5, 6, 7
print(cc)#执行不到,抛出StopIteration异常

out:

-> start

5

-> recived 5 6

11

-> recived 5 6 7

之前说过,最后会抛出一个StopIteration异常,未处理的异常会向上冒泡,传给next函数或send函数的调用方。终止协程可以发送某个哨符,让协程退出,比如内置的None和Ellipsis等常量

还有两个和异常相关的方法generator.throw(Exctpiton)和generator.close()

大概作用就是前一个会在暂停的yield出抛出指定的异常。如果生成器处理了该异常,则代码会执行到下一个yield

而产出的值(value,异常的一个属性)会成为调用 generator.throw方法得到的返回值。没处理则往上冒泡。

第二个的作用是致使生成器在暂停的 yield 表达式处抛出 GeneratorExit 异常。如果生成器没有处理这个异常,或者抛出了 StopIteration 异常(通常是指运行到结尾),调用方不会报错。

如果收到 GeneratorExit 异常,生成器一定不能产出值,否则解释器会抛出RuntimeError 异常。生成器抛出的其他异常会向上冒泡,传给调用方。

以下是找到的一段事例代码

class DemoException(Exception):
    """
    custom exception
    """
    pass

def handle_exception():
    print(‘-> start‘)

    while True:
        try:
            x = yield
        except DemoException:
            print(‘-> run demo exception‘)
        else:
            print(‘-> recived x:‘, x)

    raise RuntimeError(‘this line should never run‘)

he = handle_exception()
next(he)
he.send(10) # recived x: 10
he.send(20) # recived x: 20

he.throw(DemoException) # run demo exception

he.send(40) # recived x: 40
he.close()

yield from

相对于yield,yield from就相当于在调用方和生成器之间多了一层“通道”类似的代理。(又或者说在主线程和协程之间)

使用的渠道:比如委派生成器。

1,定义一个生成器(含yield)可以一次次的接收调用方传来的值(通过yield)和return回去处理后的值

2,定义个委派生成器,只需要yield from 生成器即可使用并接收值

3,调用委派生成器使用

未完待续

原文地址:https://www.cnblogs.com/slose-notes/p/9672312.html

时间: 2024-08-29 10:30:11

Python学习之路-随笔03 多线程/进程和协程(上篇)的相关文章

python开发之路之线程、进程、协程

一.多进程和多线程 共同点: 让多个CPU同时处理请求 区别: 1.多线程中的线程在内存空间这一点上是共享的,进程与进程使用的是不同的内存空间.即创建线程不需要开辟内存空间,而创建新的进程需要为其分配新的内存空间 全局解释器锁(GIL) 在每一个进程的“出口”,是python特有的.它的作用是:做到了1个限制,什么限制呢,如果有2个线程同时被调度了,此时全局解释器锁就限制同时只能有1个穿过全局解释器锁,才能被CPU调度 那什么时候该使用多进程,什么时候该使用多线程呢? I/O密集型用多线程 计算

Python_oldboy_自动化运维之路_线程,进程,协程(十一)

本节内容: 线程 进程 协程 IO多路复用 自定义异步非阻塞的框架 线程和进程的介绍: 举个例子,拿甄嬛传举列线程和进程的关系: 总结:1.工作最小单元是线程,进程说白了就是提供资源的 2.一个应用程序至少有一个进程,一个进程里至少有一个线程 3.应用场景:io密集型适合用多线程,计算密集型(cpu)适合用多进程 4.GIL:全局解释器锁,作用:保证同一个进程中只能有一个线程同时被调用 5.python的一个诟病:前提是被cpu调度,因为有GIL,一个应用只有一个进程,纵容有多个线程,也体现不出

Python学习之路——基础03篇

python中自然也可以像其他语言中进行整除和取模,在python中尤其要注意代码的格式和if语句的使用,稍有不但,程序逻辑就会出错. #!usr/bin/env python 3.6 # -*- coding: -utf8- -*- x=input() a=int(x[0]) b=int(x[2]) c=a%b if c==0: print('YES') else: print('NO')

Python之路【第七篇】:线程、进程和协程

Python之路[第七篇]:线程.进程和协程 Python线程 Threading用于提供线程相关的操作,线程是应用程序中工作的最小单元. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 #!/usr/bin/env python # -*- coding:utf-8 -*- import threading import time   def show(arg):     time.sleep(1)     print 'thread'+str(arg)   for i in

哗啦啦Python之路 - 线程,进程,协程

1. 线程锁 如果不控制多个线程对同一资源进行访问的话,会对数据造成破坏,使得线程运行的结果不可预期.因此要引进线程锁. 线程同步能够保证多个线程安全访问竞争资源,最简单的同步机制是引入互斥锁. 互斥锁为资源引入一个状态:锁定/非锁定.某个线程要更改共享数据时,先将其锁定,此时资源的状态为“锁定”,其他线程不能更改:直到该线程释放资源,将 资源的状态变成“非锁定”,其他的线程才能再次锁定该资源.互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性. 未引入锁前: impo

Python菜鸟之路:Python基础-线程、进程、协程

上节内容,简单的介绍了线程和进程,并且介绍了Python中的GIL机制.本节详细介绍线程.进程以及协程的概念及实现. 线程 基本使用 方法1: 创建一个threading.Thread对象,在它的初始化函数(__init__)中将可调用对象作为参数传入 import threading import time def worker(): time.sleep(2) print("test") for i in range(5): t = threading.Thread(target=

python运维开发(十)----IO多路复用多线程、进程、协程

内容目录: python作用域 python2.7和python3.5的多继承区别 IO多路复用 多线程.进程.协程 python作用域  python中无块级作用域 if 1 == 1: name = 'jabe' print(name) #可以正常输出jabe #在python中无块级作用域 #在c#或者java中是不能这样使用的,提示name未定义的 python中以函数为作用域 def func(): name = 'jbae' func() print(name) #会提示name为定

Python学习之路-Day1-Python基础

Python学习之路第一天 学习内容: 1.Python简介 2.安装 3.第一个Python程序 4.变量 5.字符编码 6.用户输入 7.表达式if..else语句 8.表达式for语句 9.break和continue 10.while循环 11.字符串格式化 1.python简介 python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏姆为了在阿姆斯特丹打发时间,决心开发一个新的脚本解释程序,作为ABC语言的一种继承. 最新的TIOB

Python学习之路

Python学习之路 目录 Python学习之路[第一篇]:流程控制,用户交互,语法要求,变量,字符,注释,模块导入的使用 Python学习之路[第二篇]:文件,字符串,列表,元组,字典,集合的使用 更新中...