python的进程,线程,和协程

@多任务的概念
操作系统同时可以运行多个任务
1,单核cpu实现多任务原理操作系统让各任务在cpu中轮流执行,因为速度太快而被认为各任务是同时实现的

  • 并发:看上去一起执行,任务数多于cpu核心数
  • 并行:真正一起执行,任务数小于等于cpu核心数
    @实现任务的方式
    1,多进程方式
    2,多线程方式
    3,协程模式
    4,多进程+多线程
    @进程的概念
    对于操作系统来说,一个任务就是一个进程。
    进程是系统中程序执行和资源分配的基本单位,每个进程都有自己的数据段,代码段,和堆栈段。
    @进程的实现
    常用的是multprocessingku,它是跨平台版本的多进程模块,提供了一个Process类来代表一个进程对象
#导如Process库
from multprocessing import Process
#创建子进程,target说明进程执行的任务
p = Process(target=fnc,arg=(,))
#启动进程
p.start()
#标识等待子进程执行完主进程才能执行完
p.join()

ps: os的库内方法可以获取进程ip

import os
#获取当前进程的id号
pip = os.getpid()
#获取当前进程的主进程ip
pipp = os.getppid()

@进程执行过程的先后顺序
各进程执行是没有顺序的,我们可以在每个进程后面加上join方法让子进程完成后主进程才能结束
父进程的执行完成不会影响子进程,但常规下主进程是不执行主要任务的,它的功能是分配任务给子进程去干,所有总逻辑上来看,主进程应该是最后结束比较好

@进程的全局变量
进程的全局比变量是不共享的,当子进程需要用到全局变量时,会拷贝一个全局变量使用当不会影响到全局变量
@进程的进程池POOL

#导入Pool库
from multprocessing import Pool
#创建多进程池
p = Pool(x)//x是自定义的cpu核心数,默认是本机的核心数,表示可以同时执行多少个进程
#创建进程,放入进程池表示同意管理
pp.apply_async(fnc,arg=(,))
#在调用join之前必须先调用close,调用close之后就不能再继续添加新的进程了
pp.close()
#进程池对象调用join方法,会等待进程池内所有的子进程结束后再去执行父进程
pp.join()

ps:当任务量较少时使用进程时,效率可能比单进程的还慢,因为创建进程很好是,耗资源的,进程数多的话,cpu会大部分用于切换进程,而用于执行的反而少了
@强制结束进程
当进程是个死循环是,无法等待其结束,只能强制结束
使用pr.terminate()
@线程的概念
在一个进程的内部,要同时干多件事,就需要同时运行多个“子任务”,我们把进程内的这些“子任务”叫做线程
线程通常叫做轻型的进程。线程是共享内存空间的并发执行的多任务,没一个线程都共享一个进程的资源。
线程是最小的执行单元,而进程有至少一个线程组成,如何调度进程和线程完全由操作系统决定,程序自己不能决定什么时候执行,执行多长时间

  • 模块
1,_thread模块   低级模块(比较接近底层)
2,threading模块  高级模块(对_thread模块的封装)

@线程的实现
任何进程默认救护启动一个主线程,主线可以启动新的子进程

#导入threading库
import threading
#current_thread()返回当前线程的实例
threading.current_thread().name//查看当前进程的name
#创建子线程
t = threading.Thread(target=fnc,arg=(,))
#启动线程
t = start()
#等待线程结束
t = join()

@多线程的数据共享
多线程中,所有变量都由所有线程共享。所有,任何一个变量都可以被任意线程修改,因此,线程之间共享数据的最大危险在于多个线程同时修改一个变量,容易把数据混乱。
@线程锁解决数据混乱
对线程执行的数据运算进行枷锁 ,加了锁的运算必须等一个线程执行完才能由其它线程使用,这样多线程变成单线程执行效率降低
由于可以存在多个锁,不同线程持有不同的锁,并试图获取其它锁,了能造成死锁,导致多个线程挂起,只能靠操作系统强制终止。

第一种锁
#创建一个锁对象
lock = threading.Lock()
for i in range(100000):
    #进行枷锁
    lock.acquire()
    try://为保险锁完后完解锁,或是出错完成不了解锁使用try     
        num = num +n
        num = num -n
    finally:
        #修改完一定要释放锁
        lock.release()
第二种锁
#实现的功能和第一种方法一样,不过with lock可以自动上锁与解锁,减少死锁几率
    with lock:
        num = num +n
        num = num -n

@完美解决线程的数据共享
使用ThreadLoocal对象

#创建一个全局的ThreadLoocal对象,每个线程有独立的存储空间,每个线程对ThreadLoocal对象都可以读写,但互不影响
local = thread.Loocal()
#把全局变量赋值给local
local.x = num //给线程增加x属性
#当线程需要调用全局变量时,把loca.x当成num调用,local就是线程的局部变量

@自定义控制线程数量
对于一个进程,我们可以规定使用多少个线程去执行
使用sem = threading.Semaphore(x) x是自定义的线程数
在调用线程的方法内增加with sem

def fnc():
    with sem:

@存够一定数量再执行
等待线程数量达到规定数量时再执行wait()后面的
使用bar= threading.Barrier(x) x是自定义等待的线程数
在调用线程的方法内增加bar.wait()

def fnc():
    print(1)
    bar.wait()
    print(2)
#线程会全部执行print(1)然后等待线程数达到x个才去执行print(2)

@定时线程
线程在指定时间后执行单位为秒
使用t = threading.Timer(5,fnc)//fnc在5秒后执行
@线程通信
卡住不让程序往下执行,必须等到事件信号后才能执行

def fnc():
    #事件对象
    event = threading.Event()
    def run():
        for i in range(5):
            #等待事件触发信号
            event.wait()
            #重置信号,不重置的话下次就不卡了,等同于正常运行,不需要再等待触发事件
            event.clear()
            print("sunck is a good man !!%d"%i)
    t = threading.Thread(target=run).start()
    return event
e = fnc()
#触发事件
e.set()//每次执行一次触发一次

@线程调度
安排不同线程以指定的秩序执行
使用线程条件变量cond = threading.Condition() 控制

def run1():
    with cond:
    for i in range (0,10,2):
        print(threading.current_thread().name,i)
        time.sleep()
        cond.wati()// 第一步,上面执行完,进入休眠
        cond.notify()//第四步,本部分第二次执行完,给自己打标签表明我执行过了

def run2():
    with cond:
    for i in range (1,10,2):
        print(threading.current_thread().name,i)
        time.sleep()
        cond.notify()// 第二步,给自己打标签表明,表明自己执行过了
        cond.wait()//第三部,进入休眠

一个简单的线程调度就是这样一个过程

@进程和线程的比较

@多任务的实现原理
通常我们会设计Master-Worker模式,Master负责分配任务,Worker负责执行任务,因此,多任务环境下,通常hi一个Master,多个Worker
@多进程
1,主进程就是Master,其它进程就是Worker
2,优点

  • 稳定性高
    一份子进程崩溃了,不会影响主进程和其它子进程,如果主进程挂了,所有进程都得挂。

3,缺点
- 创建进程代价大
在Unix/Linux系统下,用fork调用还行,在Windows下创建进程开销巨大

  • 操作系统能同时运行进程数量有限
    在内存和cpu限制下,如果有几千个进程同时运行,操作系统连调度都成问题
    @多线程
    1,主线程就是Master,其它线程就是Worker
    2,优点
  • 多线程模式通常比多进程块一点,但也块不到哪去
  • 在Windows下,多线程的效率比多进程更高
    3,缺点

  • 任何一个线程挂掉都可能直接造成整个进程崩溃
    @协程
    协程只有一个线程,在不引用或调用的情况下,完成同样的效果,因为只有一个线程,所有不存在变量冲突,自己只用一个资源,效率极高

def run():
    print(1)
    yield 10 
    print(2)
    yield 20    
    print(3)
    yield 30 
#协程的最简单风格,控制函数的阶段执行,节约线程或者进程的切换
m = rum()//返回值是一个生成器
print(next(m))// 1 10   一个线程
print(next(m))// 2 20   一个线程
print(next(m))// 3 30   一个线程

@数据的传输

def run():
    #空变量,存储的作用data始终为空
def run():
    data =''
    r = yield data
    #r=a
    print(1,r,data)
    r = yield data
    #r =b
    print(2,r,data)
    r = yield data
    #r =c
    print(3,r,data)

#启动m
m = run()
print(m.send(None))
print(m.send('a'))
print(m.send('b'))
print(m.send('c'))

@协程的数据传输实例

def product():
    c.send(None)  
    for i in range(5):
        print("成产者产生数据%d"%i)  
        r = c.send(str(i))  
        print("消费者消费了数据%s"%r)
    c.close()
def customer():
    data=""    
    while True:  
        n =yield data 
        if not n:
            return
        print("消费者消费了%s"%n)
        data = "200"
c = customer()//产生消费者
product(c)

输出

成产者产生数据0
消费者消费了0
消费者消费了数据200
成产者产生数据1
消费者消费了1
消费者消费了数据200
成产者产生数据2
消费者消费了2
消费者消费了数据200
成产者产生数据3
消费者消费了3
消费者消费了数据200
成产者产生数据4
消费者消费了4
消费者消费了数据200

过程:
这里写图片描述

猜你喜欢

转载自blog.csdn.net/qq_39222965/article/details/80508153