进程 线程 协程

进程 线程 协程

进程

'''
单核:多个任务:分时间片区执行任务----并发
多核:一个核执行一个任务(任务数和核数一样的情况)---并行,若任务太多,也是并发。
并发:分时间片区执行任务(假同时)
并行:一个核执行一个任务(任务数和核数一样的情况)--真同时
同步:在代码中指的是   依次执行---》单任务
异步:在代码中指单是   同时执行---》多任务

---分析代码时都以并行来看
import multiprocessing
多进程实现:
   进程是一个具有独立功能的程序关于某个数据集合的一次运行活动。
   它是操作系统动态执行的基本单元,在传统的操作系统中,进程即是
   基本的分配单元,也是基本的执行单元。

   多进程:正在执行的程序
         进程注意点:
            例子:-------------------3_体验_边唱边跳.py-------------------
            ----进程的创建
                import multiprocessing
                .....
                if __name__ == '__main__':
                    进程对象名 = multiprocessing.Procrss(group = None,target = 任务名,args = (元组传参),kwargs(字典传参))
                       ---创建对象用到的参数:--------6_给进程任务传参.py---------
                             group:不用传,若要传就传 group = None
                             target:函数名  target = 函数名
                             name:进程名,也可以不用设置,因为默认就有 , name = '取的名字'
                             args:以元组方式给函数传参--->真元组   args = ( ,)
                             kwargs:以字典形式给函数传参----》真字典   kwargs = { ; , : }

            ----进程的启动:进程对象名.start(),启动进程
            ----进程的限制:进程对象.join()----等对象进程执行完,才执行下面的代码
            ----进程提前结束:进程对象.terminate()----结束进程,需要在主进程中使用,不能在子进程函数中去结束自己
            ----进程开启守护模式:进程对象.daemon = True,---开启守护模式,即如果设置了这个的进程,在主进程执行完后,和主进程一起结束,不管其执行完与否
            ----程序强制退出;exit(),对多进程没有用,主进程还是要等子进程执行完后才结束 ----退出程序--------------4_论证主程序的退出.py-------------

            ----进程注意点:
                资源不共享性与互不相联系性:
                   进程是独立的,当我们新建进程的时候,进程会自己开辟一个内存空间,
                   然后会把资源拷贝到自己的内存空间里面的去,因此变量的改变不会和其它
                   进程和主进程的变量产生干扰,因此子进程与子进程之前没有联系不能以打
                   印的顺序来推出进程执行的顺序,那是他们抢执行接口的结果,他们两者是
                   没有任何关系。

                主进程:
                   不会等待子进程结束再去完成自己的代码,只发号命令,然后就开始执行自己的任务
                   主进程会等待所有子进程执行完毕后,再退出

            ----进程编号和当前进程的获取
                multiprocessing.current_process()----获取当前执行任务的进程对象
                multiprocessing.current_process().pid----获取当前执行任务的进程对象的编码
                os.getpid()----获取当前执行函数的编码
                os.getppid()----获取当前执行进程的父进程编码

    --子进程之间实现通信:queue

        que = multiprocessing.Queue(n) # n表示队列的大小,如果不写就是无限队列
        基本语法
           que.put('加入的值-任意值')
           que.get('取出的值’)  #  相当于队列,先进先出
           que.put_nowait() # 强行添加;若队列满了,再强行添加,会阻塞,报错
           que.get_nowait() # 强行取值;若队列空了,再强行取值,报错

           que.full() #返回队列是否是满的
           que.empty() #返回队列是否为空
           que.qsize() #返回队列的大小 # 此语法在mac上无法使用

        注意点:当队列已经满了再往里面加值,会让代码执行产生阻塞,这个时候需要其它队列从离main取出一个值,这个队列后面的代码彩壳正常执行

        实际例子--一个进程向队列中传值,一个进程取值另一个:
        import multiprocessing

        def add(que):
            print(multiprocessing.current_process().name)#打印当前执行任务的名字
            que.put('a')#向队列中插入值

        def take(que):
            print(multiprocessing.current_process().name)#打印当前执行任务的名字
            print(que.get('a'))#向队列中取出值

        if __name__=='__main__':
            #创建通信队列
            que = multiprocessing.Queue(3)
            #创建子进程
            p1 = multiprocessing.Process(target = add , args = (que,),name = '向队列中加入值')#传入队列对象
            p2 = multiprocessing.Process(target = take, args = (que,),name = '向队列中取出值')#传入队列对象
            #队列执行
            p1.start()
            p2.start()

        ---代码执行:
             向队列中加入值
             向队列中取出值
             a

    --进程池:

      在定义的李时候里面会有很多进程,在任务分配的时候,程序根据任务量的多少来决定使用进程的个数与次数,提高执行效率。
      --------注意:进程池里面所有的子进程都具有保护性,就是与主进程同生死,因此一定要记住使用join函数
      --常用函数
           pool.join() #我任务量就这么多了,你们等我弄完。
           pool.close() #关闭进程池,这样可以避免后面的代码的执行,受到进程池任务分配完与否等稳定而收到干扰
           pool.apply_async(任务名,args,kwargs)  # 给池中进程分配任务       【asynschronous】异步
           pool.apply() 同步执行,不推荐,因为这样和多进程顺序进行没有区别

      实际例子--进程池的异步执行:
      #拷贝

'''

#多进程的体验

import multiprocessing
import time
import os

a = []
def dance():
   for i in range(5):
       a.append(i)
       #multiprocessing.current_process().pid  os.getpid()-获取当前进程编号   os.getppid()--获取父进程编号
       print('跳舞。。。。',a,multiprocessing.current_process(),multiprocessing.current_process().pid,os.getpid(),os.getppid())
       time.sleep(1)
def sing():
   for i in range(5):
       a.append(i)
       print('唱歌。。。。',a,multiprocessing.current_process(),multiprocessing.current_process().pid,os.getpid(),os.getppid())
       time.sleep(1)

#有时候可能两个进程在某一瞬间同时执行---》唱歌 跳舞一起出现
if __name__ == '__main__':
   p1 = multiprocessing.Process(target = dance)
   p2 = multiprocessing.Process(target = sing)
   p1.start()
   p2.start()



#文件的拷贝
import multiprocessing
import os

#初始路径
path = r'/Users/manblue/Downloads/a'
targ = r'/Users/manblue/Downloads/b'

#拷贝
def copy(name):
   abs_path = os.path.join(path,name)
   abs_targ = os.path.join(targ,name)
   with open(abs_path,'rb') as file_r:
       with open(abs_targ,'wb') as file_w:
           data = file_r.read()
           file_w.write(data)

if __name__=="__main__":
   #创建进程池
   pool = multiprocessing.Pool(3)
   if not os.path.exists(targ):
       os.mkdir(targ)
   name_li = os.listdir(path)
   #进程池分配任务
   for name in name_li:
       pool.apply_async(copy,(name,))
   #关闭进程池
   pool.close()
   pool.join()



'''
拷贝文件---进程池---多层目录

1、运用什么方式更快-----多进程/多线程。------进程池
2、怎样拷贝文件-----对文件内部进行遍历----判断文件/文件夹
    -----若文件夹是大文件,还得慢慢拷贝,就是while循环拷贝
3、创建或读取文件
'''
import multiprocessing
import os


def copy(name,path,targ):
   print(multiprocessing.current_process().name,"正在光荣对完成使命")
   #得到起始路径和目标路径的绝对路径
   abs_path = os.path.join(path,name)
   abs_targ = os.path.join(targ,name)

   if os.path.isdir(abs_path):
       os.mkdir(abs_targ)
       name_li = os.listdir(abs_path)
       #判断是否是空
       if name_li:
           path = abs_path
           targ = abs_targ
           for name in name_li:
               copy(name,path,targ)
   else:
       with open(abs_path,'r') as file_r:
           with open(abs_targ,'a') as file_w:
               while True:
                   content = file_r.read(6)
                   if content:
                       file_w.write(content)
                   else:
                       print("拷贝完成")
                       break



if __name__ == '__main__':
   path = r'a'
   targ = r'b'

   #创立质量拷贝的方法渠道
   pool = multiprocessing.Pool(3)

   #确保目标路径存在
   if not os.path.exists(targ):
       os.mkdir(targ)

   #分配工作
   name_li = os.listdir(path)
   for name in name_li:
       pool.apply_async(copy,(name,path,targ))

   #拷贝完后得关闭进程池,且进程池里面对都是保护性质,即主进程执行完就跟着结束
   pool.close()
   pool.join()#阻断主进程提前结束

线程

'''
线程

在一个进程内部,要同时干多件事情,就需要同时运行多个子任务,我们把进程内的这些子任务叫做线程
多线程就是为了同步完成多项任务(在单个程序中同时运行多个线程完成不同的任务和工作),不是为了提高运行效率,而是为了提高资源使用效率来提高系统的效率

线程存在于进程当中,同属一个进程下的线程之间共享进程资源

线程的创建:
线程对象名 = threading.Thread(group=None,target = dance, args = (...), kwargs = {...}, name = '...')

线程调用
线程对象.start()

线程的传参
创建线程传参:和进程一摸一样
group = None
target = 任务名
args = () - -真元组
kwargs = {} - -真字典

获取活动线程的列表和获取活动线程的数量:活动线程,即正在执行的线程
活动线程列表:
threading.enumerate()
活动线程数量:
threading.active_count()

主线程会等子线程结束后再结束
设置保护属性(同生共死)
# threading.Tread(...,deamon = True)
# 线程对象.setDeamon(True)
# 线程对象.deamon =True

子线程之间:
资源共享
问题:会出现抢占资源的问题 - --解决问题用互斥锁

互斥锁: 对共享数据进行锁定,保证同一时刻只能有一个线程去操作

可以解决线程互相抢资源的问题,被锁祝的资源只能当前线程用,等用完了解锁在抢
创建:lock_name = threading.Lock()
上锁:lock_name.acquires()
----尽量不要让任务中所有代码都锁住,只能锁住部分数据出错的地方
开锁:lock_name.release()
死锁:一直等待对方释放锁的情景,死锁一旦发生,程序就会停止响应
------------------解决:判断的每一个分支都应该释放锁。

'''
'''
获取活动线程列表 ----- threading.enumerate()
获取活动线程数量------threading.active_count()
'''
import threading
import time

def dance():
   for _ in range(5):
       print('dance',threading.current_thread().name)
       time.sleep(0.5)

def sing():
   for _ in range(5):
       print('sing',threading.current_thread().name)
       time.sleep(0.5)

print(threading.enumerate(),threading.active_count())
t1 = threading.Thread(target = dance,name = 't1')
t2 = threading.Thread(target = sing,name = 't2')
t1.start()
print(threading.enumerate(),threading.active_count())
t2.start()
print(threading.enumerate(),threading.active_count())

协程

#进程(process)>线程(thread)>协程(生成器)
'''
   协程--微线程
   只有在耗时操作的时候需要使用协程(如网络请求 网络下载 网络上传如爬虫/其它iO操作)
   是一种用户态的轻量级线程,协程的调度完全由用户控制(进程和线程都是由cpu
   内核进行调度)。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,
   在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,
   可以不加锁的访问全局变量,所以上下文的切换非常快。-------即出现耗时操作时立马进行切换,让cpu不再闲着,高效率利用cpu

   表现方式 - -1:
   while True:
       def 函数1:

       ......
       yield

   def 函数2:

   ......
   yield
   greenlet

   和生成器差不多,只是这个执行时只需执行一个,   对象.switch(), 还是需要人工切换任务,
   import greenlet
   对象名 = greenlet.greenlet(任务名也就是函数名),一个对象对应一个任务

   执行,只需执行一个,另一个会自动跳转 - ----对象名.switch()

   gevent
   可以自动识别延时操作比如sleep() 网络的请求
   IO操作。如果发现在代码中有等待阻塞,那么会自动切到下一个任务中去
   import gevent  # 导入包
   from gevent import monkey  # 导入补丁
   monkey.patch_all()  # 打入补丁

   def 函数1(

       ):
   函数体(得有sllep() 网络请求
   IO等操作)

   def 函数2(

       ):
   函数体(得有sllep() 网络请求
   IO等操作)
   g1 = gevent.spaen(函数名)
   g2 = gevent.spaen(函数名)

   g1.join()
   g2.join()
'''
#下载并调用greenlet模块----优点:只需调用一次 缺点:需要人工switch切换
from greenlet import greenlet


def homepage():
   print("34")
   gr2.switch()
   print("12")
   gr3.switch()


def bbs():
   print("84")
   gr3.switch()
   print("13")


def login():
   print("56")
   gr1.switch()
   print("--end--")


gr1 = greenlet(homepage)
gr2 = greenlet(bbs)
gr3 = greenlet(login)
gr1.switch()

#下载并调用greenlet模块
import gevent
import time
#如果没有这个补丁它不会来回跳转,需要等一个线程执行完后才执行另一个,这个补丁是后来对模块的修复,因此代码需要单独
from gevent import monkey#导入补丁
monkey.patch_all()#将补丁先打入到程序中

def func_01():
   while True:
       print('we chat')
       gevent.sleep(0.5)# gevent会自动识别这些,然后会自动跳转到下一个任务
def func_02():
   while True:
       print('chat 记录')
       gevent.sleep(0.5)# gevent会自动识别这些,然后会自动跳转到下一个任务

g1 = gevent.spawn(func_01)#创建gevent对象
g2 = gevent.spawn(func_02)

#启动,固定语法
g1.join() # join()之后才跳转,
g2.join() # join()之后才跳转,

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值