高档软件工程第2次作业王者荣耀

三 并发与相互

无论并行照旧出现,在用户看来都以’同时’运转的,不管是进度依旧线程,都只是3个职分而已,真是干活的是cpu,cpu来做那个职务,而二个cpu同方今刻只可以进行贰个职分

      一
并发:是伪并行,即看起来是还要运营。单个cpu+多道技术就能够完毕产出,(并行也属于并发)

     二 并行:同时运营,唯有具有四个cpu才能落到实处彼此之间

       
 单核下,可以动用多道技术,多少个核,各样核也都足以选取多道技术(多道技术是本着单核而言的

       
 有八个核,两个任务,这样同最近间有多个职务被执行,若是分别被分配给了cpu1,cpu2,cpu3,cpu4,

       
 一旦职分1相见I/O就被迫暂停执行,此时职分5就获得cpu1的光阴片去执行,那正是单核下的多道技术

       
 而一旦职务1的I/O结束了,操作系统会另行调用它(需知进度的调度、分配给哪个cpu运营,由操作系统说了算),只怕被分配给多少个cpu中的任意1个去实践

  王者荣耀 1

具有现代计算机平常会在同权且间做过多件事,贰个用户的PC(无论是单cpu依旧多cpu),都得以同时运维八个职务(1个职责能够领会为一个经过)。

    运维3个进度来杀毒(360软件)

    运行多少个进度来看电影(沙尘卷风影音)

    运维贰个经过来聊天(腾讯QQ)

富有的这几个经过都需被管制,于是三个帮助多进度的多道程序系统是主要的

多道技术概念回看:内部存款和储蓄器中同时存入多道(多少个)程序,cpu从二个经过连忙切换来此外三个,使每种进度各自运转几十或几百皮秒,那样,尽管在某一个时而,二个cpu只好执行叁个职责,但在1秒内,cpu却能够运营三个进程,这就给人发生了互相的错觉,即伪并发,以此来区别多处理器操作系统的确实硬件并行(两个cpu共享同一个大体内部存款和储蓄器)

1.您对您的高等学校生活有何样想要吐槽的地点吗?你精彩的高校教育应当是什么体统的?跟高校给你的有何区别?比较你在中中原人民共和国民代表大会学的经验,你的教育工小编和学院和学校能不负众望和海外那样吗?假诺无法,请分析一下为何。(必答)

  作者的大学生活过得还算罗曼蒂克,对于爱好的课风雨无阻,认真读书每一个知识点,觉得很无聊的课,嘿嘿,你们知道。课余时间偶尔和同班开黑,偶尔出去逛逛,越来越多的时候是在网上膜拜大牛们做出来的非凡cool的东西,然后本身修修改改地模拟,唯一吐槽的地方就是故乡到高校并未直达车,每一回都得先坐到新加坡西站,然后坐大巴到东京站再转,最痛楚的时候是抢不到火车票(离乡土太远)。理想中的大学总计机教育应该还要包含部分人文类课程和标准理论课以及提供越多的正儿八经实践,这样才能够将大学生培养成不仅有实干编制程序能力,还有更强改进能力以及更广大视野的新世纪人才。大学四年的经验,觉得师生之间的关联很难形成海外师生间那种君子之交的关系,外国的助教范专校勘和注释于学术,和学生的调换越来越多,师生间频还是可以为三个标题争得面红耳赤,而境内的学员会觉得老师有一种权威感、距离感,学生的独立自主能动性也未曾国外学生强,所以很难。

八 共享数据

展望现在,基于音讯传递的出现编制程序是毫无疑问

即便是使用线程,推荐做法也是将顺序设计为大气单独的线程集合

透过信息队列交换数据。那样石破天惊地减弱了对使用锁定和别的共同手段的须求,

仍是能够扩展到分布式系统中

经过间通讯应该尽量防止使用本节所讲的共享数据的艺术

进程间数据是独立的,可以借助于队列或管道实现通信,二者都是基于消息传递的

虽然进程间数据独立,但可以通过Manager实现数据共享,事实上Manager的功能远不止于此

A manager object returned by Manager() controls a server process which holds Python objects and allows other processes to manipulate them using proxies.

A manager returned by Manager() will support types list, dict, Namespace, Lock, RLock, Semaphore, BoundedSemaphore, Condition, Event, Barrier, Queue, Value and Array. For example,

#进程之间操作共享的数据

from multiprocessing import Manager,Process,Lock
import os
def work(d,lock):
    # with lock: #不加锁而操作共享的数据,肯定会出现数据错乱
        d['count']-=1

if __name__ == '__main__':
    lock=Lock()
    with Manager() as m:
        dic=m.dict({'count':100})
        p_l=[]
        for i in range(100):
            p=Process(target=work,args=(dic,lock))
            p_l.append(p)
            p.start()
        for p in p_l:
            p.join()
        print(dic)
        #{'count': 94}

 

Operating Systems(操作系统)

  起始接触的手提式有线电电话机系统是MediaTek系统,最新接触的电脑系统是windows
XP系统,操作系统更新换代,在高等高校的时候接触到了Linux系统,Linux系统有不少的发行版本,红帽、CentOS、Ubuntu等等。笔者想谈谈Deepin系统,原名Linux
Deepin,在2016年十一月改名Deepin。Deepin 是二个基于Linux
的操作系统,意在创制多个簇新的大概、易用、美观的Linux操作系统。Deepin是中国最活跃的
Linux 发行版,Deepin
为所有人提供稳定、高效的操作系统,强调安全、易用、赏心悦目。其口号为“免除新手难过,节约老手时间”。笔者要好认为deepin很适合刚刚接触linux的人,熟习的界面,强大的命令行。UI美貌,软件设置方便,人性化,不供给怎么折腾。今后Deepin系统排行在上升,作者以为前景的迈入会更好,愈多的人群会参与。

四 守护进程

主进度成立守护进度

  其一:守护进程会在主进程代码执行完成后就终止

  其二:守护进程内不能够再开启子进度,不然抛出很是:AssertionError:
daemonic processes are not allowed to have children

专注:进程之间是互相独立的,主进度代码运维甘休,守护进度随即终止

 

from multiprocessing import Process
import time
import random

class Piao(Process):
    def __init__(self,name):
        self.name=name
        super().__init__()
    def run(self):
        print('%s is piaoing' %self.name)
        time.sleep(random.randrange(1,3))
        print('%s is piao end' %self.name)


p=Piao('egon')
p.daemon=True #一定要在p.start()前设置,设置p为守护进程,禁止p创建子进程,并且父进程代码执行结束,p即终止运行
p.start()
print('主')

#主进程代码运行完毕,守护进程就会结束
from multiprocessing import Process
from threading import Thread
import time
def foo():
    print(123)
    time.sleep(1)
    print("end123")

def bar():
    print(456)
    time.sleep(3)
    print("end456")


p1=Process(target=foo)
p2=Process(target=bar)

p1.daemon=True
p1.start()
p2.start()
print("main-------") #打印该行则主进程代码结束,则守护进程p1应该被终止,可能会有p1任务执行的打印信息123,因为主进程打印main----时,p1也执行了,但是随即被终止

迷惑人的例子
你喜爱这一正规吗?你对电脑的挚爱是何等的?仅仅是口头的吗?

  答案是早晚的,作者忠爱总计机专业,曾经的自己也会像博主C同等会把书上代码3个3个用自个儿的手敲打三次。正是那种对总结机的爱慕,俺接纳了报考博士,继续选拔了微型总计机专业,一样再总计机领域走的更远。

三 Process类的应用

小心:在windows中Process()必须置于# if __name__ ==
‘__main__’:下

Since Windows has no fork, the multiprocessing module starts a new Python process and imports the calling module. 
If Process() gets called upon import, then this sets off an infinite succession of new processes (or until your machine runs out of resources). 
This is the reason for hiding calls to Process() inside

if __name__ == "__main__"
since statements inside this if-statement will not get called upon import.
由于Windows没有fork,多处理模块启动一个新的Python进程并导入调用模块。 
如果在导入时调用Process(),那么这将启动无限继承的新进程(或直到机器耗尽资源)。 
这是隐藏对Process()内部调用的原,使用if __name__ == “__main __”,这个if语句中的语句将不会在导入时被调用。

创设并开启子进度的三种艺术

#开进程的方法一:
import time
import random
from multiprocessing import Process
def piao(name):
    print('%s piaoing' %name)
    time.sleep(random.randrange(1,5))
    print('%s piao end' %name)



p1=Process(target=piao,args=('egon',)) #必须加,号
p2=Process(target=piao,args=('alex',))
p3=Process(target=piao,args=('wupeqi',))
p4=Process(target=piao,args=('yuanhao',))

p1.start()
p2.start()
p3.start()
p4.start()
print('主线程')

方法一

#开进程的方法二:
import time
import random
from multiprocessing import Process


class Piao(Process):
    def __init__(self,name):
        super().__init__()
        self.name=name
    def run(self):
        print('%s piaoing' %self.name)

        time.sleep(random.randrange(1,5))
        print('%s piao end' %self.name)

p1=Piao('egon')
p2=Piao('alex')
p3=Piao('wupeiqi')
p4=Piao('yuanhao')

p1.start() #start会自动调用run
p2.start()
p3.start()
p4.start()
print('主线程')

勤学苦练1:把所学的socket通讯变成并发的款式

from socket import *
from multiprocessing import Process

server=socket(AF_INET,SOCK_STREAM)
server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
server.bind(('127.0.0.1',8080))
server.listen(5)

def talk(conn,client_addr):
    while True:
        try:
            msg=conn.recv(1024)
            if not msg:break
            conn.send(msg.upper())
        except Exception:
            break

if __name__ == '__main__': #windows下start进程一定要写到这下面
    while True:
        conn,client_addr=server.accept()
        p=Process(target=talk,args=(conn,client_addr))
        p.start()

server端

from socket import *

client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8080))


while True:
    msg=input('>>: ').strip()
    if not msg:continue

    client.send(msg.encode('utf-8'))
    msg=client.recv(1024)
    print(msg.decode('utf-8'))

多个client端

每来一个客户端,都在服务端开启一个进程,如果并发来一个万个客户端,要开启一万个进程吗,你自己尝试着在你自己的机器上开启一万个,10万个进程试一试。
解决方法:进程池

Process对象的join方法

join:主进度等,等待子进度甘休

from multiprocessing import Process
import time
import random

class Piao(Process):
    def __init__(self,name):
        self.name=name
        super().__init__()
    def run(self):
        print('%s is piaoing' %self.name)
        time.sleep(random.randrange(1,3))
        print('%s is piao end' %self.name)


p=Piao('egon')
p.start()
p.join(0.0001) #等待p停止,等0.0001秒就不再等了
print('开始')

有了join,程序不正是串行了呢???

from multiprocessing import Process
import time
import random
def piao(name):
    print('%s is piaoing' %name)
    time.sleep(random.randint(1,3))
    print('%s is piao end' %name)

p1=Process(target=piao,args=('egon',))
p2=Process(target=piao,args=('alex',))
p3=Process(target=piao,args=('yuanhao',))
p4=Process(target=piao,args=('wupeiqi',))

p1.start()
p2.start()
p3.start()
p4.start()

#有的同学会有疑问:既然join是等待进程结束,那么我像下面这样写,进程不就又变成串行的了吗?
#当然不是了,必须明确:p.join()是让谁等?
#很明显p.join()是让主线程等待p的结束,卡住的是主线程而绝非进程p,

#详细解析如下:
#进程只要start就会在开始运行了,所以p1-p4.start()时,系统中已经有四个并发的进程了
#而我们p1.join()是在等p1结束,没错p1只要不结束主线程就会一直卡在原地,这也是问题的关键
#join是让主线程等,而p1-p4仍然是并发执行的,p1.join的时候,其余p2,p3,p4仍然在运行,等#p1.join结束,可能p2,p3,p4早已经结束了,这样p2.join,p3.join.p4.join直接通过检测,无需等待
# 所以4个join花费的总时间仍然是耗费时间最长的那个进程运行的时间
p1.join()
p2.join()
p3.join()
p4.join()

print('主线程')


#上述启动进程与join进程可以简写为
# p_l=[p1,p2,p3,p4]
# 
# for p in p_l:
#     p.start()
# 
# for p in p_l:
#     p.join()

 

Process对象的别的方法或性质(掌握)

terminate与is_alive

#进程对象的其他方法一:terminate,is_alive
from multiprocessing import Process
import time
import random

class Piao(Process):
    def __init__(self,name):
        self.name=name
        super().__init__()

    def run(self):
        print('%s is piaoing' %self.name)
        time.sleep(random.randrange(1,5))
        print('%s is piao end' %self.name)


p1=Piao('egon1')
p1.start()

p1.terminate()#关闭进程,不会立即关闭,所以is_alive立刻查看的结果可能还是存活
print(p1.is_alive()) #结果为True

print('开始')
print(p1.is_alive()) #结果为False

name与pid

from multiprocessing import Process
import time
import random
class Piao(Process):
    def __init__(self,name):
        # self.name=name
        # super().__init__() #Process的__init__方法会执行self.name=Piao-1,
        #                    #所以加到这里,会覆盖我们的self.name=name

        #为我们开启的进程设置名字的做法
        super().__init__()
        self.name=name

    def run(self):
        print('%s is piaoing' %self.name)
        time.sleep(random.randrange(1,3))
        print('%s is piao end' %self.name)

p=Piao('egon')
p.start()
print('开始')
print(p.pid) #查看pid

 

剖析软件

四 同步与异步

一同施行:三个经过在履行有个别职分时,此外一个历程必须等待其执行完结,才能继续执行
异步执行:一个进程在履行有个别任务时,别的二个进度无需等待其执行达成,就足以继续执行,当有新闻再次回到时,系统会通报后者举办处理,那样能够抓实实践作用

举个例子,打电话时便是一道通讯,发短息时正是异步通信。

Tools(工具软件)

  谈谈Sublime
Text,三个文本代码编辑器,是二个收费软件,也是HTML和随笔先进的文书编辑器。
Sublime
Text具有优良的用户界面和有力的效率,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。是一个并且帮忙Windows、Linux、Mac
OS
X等操作系统跨平台的编辑器,深受程序员的怜爱。最开头是同桌嫌弃本身的电脑卡,使用记事本又太low,所以向自己引进了Sublime
Text,小编使用之后就爱上了它,作者欣赏它的简单、体量小、代码高亮。

九 信号量(了解)

互斥锁 同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据 ,比如厕所有3个坑,那最多只允许3个人上厕所,后面的人只能等里面有人出来了才能再进去,如果指定信号量为3,那么来一个人获得一把锁,计数加1,当计数等于3时,后面的人均需要等待。一旦释放,就有人可以获得一把锁

    信号量与进程池的概念很像,但是要区分开,信号量涉及到加锁的概念

from multiprocessing import Process,Semaphore
import time,random

def go_wc(sem,user):
    sem.acquire()
    print('%s 占到一个茅坑' %user)
    time.sleep(random.randint(0,3)) #模拟每个人拉屎速度不一样,0代表有的人蹲下就起来了
    sem.release()

if __name__ == '__main__':
    sem=Semaphore(5)
    p_l=[]
    for i in range(13):
        p=Process(target=go_wc,args=(sem,'user%s' %i,))
        p.start()
        p_l.append(p)

    for i in p_l:
        i.join()
    print('============》')

信号量Semahpore(同线程一样)

率先局部:结缘计算机

二 进度与程序的区分

次第仅仅只是一堆代码而已,而经过指的是先后的周转进程。

举例:

设想一人有手腕好厨艺的电脑物文学家egon正在为他的姑娘元昊烘制千层彩虹蛋糕。

他有做生日奶油蛋糕的菜单,

厨房里拥有需的原料:面粉、鸡蛋、韭菜,蒜泥等。

在那个比喻中:

    做生日蛋糕的菜谱就是先后(即用适量格局描述的算法)

    计算机科学家便是电脑(cpu)

    而做生日蛋糕的各样原料就是输入数据

 
 进度便是厨神阅读食谱、取来各样原料以及烘制翻糖蛋糕等一八种动作的总和

 

现行只要总结机化学家egon的外甥alex哭着跑了进去,说:XXXXXXXXXXXXXX

物史学家egon想了想,处理外甥alex蛰伤的职务比给闺女元昊做千层蛋糕的职务更要紧,于是

电脑科学家就记录下她照着食谱做到哪儿了(保存进程的此时此刻事态),然后拿出一本急救手册,根据内部的指令处理蛰伤。那里,大家来看处理机从二个进度(做彩虹蛋糕)切换成另贰个高优先级的进程(实施治疗抢救和治疗),每个进度具有各自的先后(食谱和救治手册)。当蜜蜂蛰伤处理完事后,那位处理器化学家又回到做生日蛋糕,从她
距离时的那一步继续做下来。

急需强调的是:同三个程序执行四遍,那也是五个进度,比如打开暴风影音,尽管都是同七个软件,可是三个方可播放泷口光,二个能够播放吉川萌。

 

2.电脑是您欣赏的天地啊?是你擅长的园地呢?

  接触的小圈子不是不计其数,如今而言,未来如故很喜爱计算机领域,毕竟高校四年大致接触的都以电脑有关的文化。笔者记得最开首喜欢上编制程序的时候是在大学一年级,当时高校长办公室了三个顺序设计竞赛,鼓励新生参加,奖品丰饶,能够在宿舍参预竞技。当时就觉着好奇好玩就插手了,当时共同容易的数学题,好像是用10元钱恰好可以各买多少本单价1.7元和0.5元的脚本。当时和好笔算都能算出答案,但正是不晓得怎么编制程序去求解。后来看见外人的代码就感觉到编制程序语言的吸重力和强大,就那样爱上了编制程序。在高等高校四年中学到了很多,但总计机世界挺常见的,学无穷境,谈不上什么擅长。

一 、理论部分

答疑难题:构成个人经历写一篇博客谈谈自身的感想

二 、代码知识部分

Games(游戏)

  游戏陪伴笔者度过了光明的幼时,贪吃蛇、俄罗丝方块、魂斗罗的上上下下左右左右BABA、定时收菜偷菜……游戏软件项目繁多,初级中学的时候本身玩过CF(穿越火线),高级中学的时候玩过QQ飞车和炫舞,到了高校接触了LOL(英雄结盟)、炉石好玩的事、皇室战争,现在迷恋王者荣耀。游戏软件有早晚的生命期,小编玩的都是下载免费,但其中的道具是必要收费的。充钱可以变得更强,不想花钱的就要求大批量的时刻。这也是娱乐行业失去一些玩家的成分,但那也是他俩赚钱的不可或缺措施。但进口游戏公司缺少更新,许多戏耍和国外的玩乐相似,他们会在嬉戏收费方面下武功,盈利为主。那几个往往导致一些游玩的生产周期短,失去了大气的游玩玩家。

十一 进程池

在动用Python实行系统一管理理的时候,特别是还要操作七个文件目录,或然远程序控制制多台主机,并行操作能够节约大批量的时光。多进度是落实产出的伎俩之一,供给留意的题材是:

  1. 很精通需求出现执行的任务日常要远大于核数
  2. 贰个操作系统不容许极端开启进度,经常有几个核就开多少个经过
  3. 进度开启过多,功用反而会下滑(开启进度是要求占用系统能源的,而且打开多余核数指标进程也不知所可到位互相)

譬如说当被操作对象数目十分小时,能够直接使用multiprocessing中的Process动态成生多少个经过,24个幸好,但借使是广大个,上千个。。。手动的去限制进度数量却又太过繁琐,此时得以表达进程池的功力。

咱俩就足以由此爱惜1个进程池来控制进程数目,比如httpd的进度方式,规定最小进度数和最大进度数… 
ps:对于远程进度调用的尖端应用程序而言,应该使用进度池,Pool能够提供钦定数量的长河,供用户调用,当有新的请求提交到pool中时,要是池还一向不满,那么就会制造1个新的经过用来执行该请求;但借使池中的进度数一度落成规定最大值,那么该请求就会等待,直到池中有进程甘休,就选定进度池中的进度。

 
  创设进度池的类:尽管钦点numprocess为3,则经过池会从无到有开创四个进程,然后自始至终使用那八个经过去实践全部职责,不会开启其余进程

1 Pool([numprocess  [,initializer [, initargs]]]):创建进程池 

    参数介绍:

1 numprocess:要创建的进程数,如果省略,将默认使用cpu_count()的值
2 initializer:是每个工作进程启动时要执行的可调用对象,默认为None
3 initargs:是要传给initializer的参数组

  方法介绍:

    重要措施:

p.apply(func [, args [, kwargs]]):在一个池工作进程中执行func(*args,**kwargs),然后返回结果。需要强调的是:此操作并不会在所有池工作进程中并执行func函数。如果要通过不同参数并发地执行func函数,必须从不同线程调用p.apply()函数或者使用p.apply_async()
p.apply_async(func [, args [, kwargs]]):在一个池工作进程中执行func(*args,**kwargs),然后返回结果。此方法的结果是AsyncResult类的实例,callback是可调用对象,接收输入参数。当func的结果变为可用时,将理解传递给callback。callback禁止执行任何阻塞操作,否则将接收其他异步操作中的结果。

p.close():关闭进程池,防止进一步操作。如果所有操作持续挂起,它们将在工作进程终止前完成
P.jion():等待所有工作进程退出。此方法只能在close()或teminate()之后调用

 别的办法(理解一些)

方法apply_async()和map_async()的返回值是AsyncResul的实例obj。实例具有以下方法
obj.get():返回结果,如果有必要则等待结果到达。timeout是可选的。如果在指定时间内还没有到达,将引发一场。如果远程操作中引发了异常,它将在调用此方法时再次被引发。
obj.ready():如果调用完成,返回True
obj.successful():如果调用完成且没有引发异常,返回True,如果在结果就绪之前调用此方法,引发异常
obj.wait([timeout]):等待结果变为可用。
obj.terminate():立即终止所有工作进程,同时不执行任何清理或结束任何挂起工作。如果p被垃圾回收,将自动调用此函数

  应用:

apply同步执行:阻塞式

from multiprocessing import Pool
import os,time
def work(n):
    print('%s run' %os.getpid())
    time.sleep(3)
    return n**2

if __name__ == '__main__':
    p=Pool(3) #进程池中从无到有创建三个进程,以后一直是这三个进程在执行任务
    res_l=[]
    for i in range(10):
        res=p.apply(work,args=(i,)) #同步运行,阻塞、直到本次任务执行完毕拿到res
        res_l.append(res)
    print(res_l)

apply_async异步执行:非阻塞

from multiprocessing import Pool
import os,time
def work(n):
    print('%s run' %os.getpid())
    time.sleep(3)
    return n**2

if __name__ == '__main__':
    p=Pool(3) #进程池中从无到有创建三个进程,以后一直是这三个进程在执行任务
    res_l=[]
    for i in range(10):
        res=p.apply_async(work,args=(i,)) #同步运行,阻塞、直到本次任务执行完毕拿到res
        res_l.append(res)

    #异步apply_async用法:如果使用异步提交的任务,主进程需要使用jion,等待进程池内任务都处理完,然后可以用get收集结果,否则,主进程结束,进程池可能还没来得及执行,也就跟着一起结束了
    p.close()
    p.join()
    for res in res_l:
        print(res.get()) #使用get来获取apply_aync的结果,如果是apply,则没有get方法,因为apply是同步执行,立刻获取结果,也根本无需get

 

详解:apply_async与apply

#一:使用进程池(非阻塞,apply_async)
#coding: utf-8
from multiprocessing import Process,Pool
import time

def func(msg):
    print( "msg:", msg)
    time.sleep(1)
    return msg

if __name__ == "__main__":
    pool = Pool(processes = 3)
    res_l=[]
    for i in range(10):
        msg = "hello %d" %(i)
        res=pool.apply_async(func, (msg, ))   #维持执行的进程总数为processes,当一个进程执行完毕后会添加新的进程进去
        res_l.append(res)
    print("==============================>") #没有后面的join,或get,则程序整体结束,进程池中的任务还没来得及全部执行完也都跟着主进程一起结束了

    pool.close() #关闭进程池,防止进一步操作。如果所有操作持续挂起,它们将在工作进程终止前完成
    pool.join()   #调用join之前,先调用close函数,否则会出错。执行完close后不会有新的进程加入到pool,join函数等待所有子进程结束

    print(res_l) #看到的是<multiprocessing.pool.ApplyResult object at 0x10357c4e0>对象组成的列表,而非最终的结果,但这一步是在join后执行的,证明结果已经计算完毕,剩下的事情就是调用每个对象下的get方法去获取结果
    for i in res_l:
        print(i.get()) #使用get来获取apply_aync的结果,如果是apply,则没有get方法,因为apply是同步执行,立刻获取结果,也根本无需get

#二:使用进程池(阻塞,apply)
#coding: utf-8
from multiprocessing import Process,Pool
import time

def func(msg):
    print( "msg:", msg)
    time.sleep(0.1)
    return msg

if __name__ == "__main__":
    pool = Pool(processes = 3)
    res_l=[]
    for i in range(10):
        msg = "hello %d" %(i)
        res=pool.apply(func, (msg, ))   #维持执行的进程总数为processes,当一个进程执行完毕后会添加新的进程进去
        res_l.append(res) #同步执行,即执行完一个拿到结果,再去执行另外一个
    print("==============================>")
    pool.close()
    pool.join()   #调用join之前,先调用close函数,否则会出错。执行完close后不会有新的进程加入到pool,join函数等待所有子进程结束

    print(res_l) #看到的就是最终的结果组成的列表
    for i in res_l: #apply是同步的,所以直接得到结果,没有get()方法
        print(i)

勤学苦练2:使用进度池维护稳定数目标长河(重写练习1)

 server端

#Pool内的进程数默认是cpu核数,假设为4(查看方法os.cpu_count())
#开启6个客户端,会发现2个客户端处于等待状态
#在每个进程内查看pid,会发现pid使用为4个,即多个客户端公用4个进程
from socket import *
from multiprocessing import Pool
import os

server=socket(AF_INET,SOCK_STREAM)
server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
server.bind(('127.0.0.1',8080))
server.listen(5)

def talk(conn,client_addr):
    print('进程pid: %s' %os.getpid())
    while True:
        try:
            msg=conn.recv(1024)
            if not msg:break
            conn.send(msg.upper())
        except Exception:
            break

if __name__ == '__main__':
    p=Pool()
    while True:
        conn,client_addr=server.accept()
        p.apply_async(talk,args=(conn,client_addr))
        # p.apply(talk,args=(conn,client_addr)) #同步的话,则同一时间只有一个客户端能访问

 

客户端

from socket import *

client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8080))


while True:
    msg=input('>>: ').strip()
    if not msg:continue

    client.send(msg.encode('utf-8'))
    msg=client.recv(1024)
    print(msg.decode('utf-8'))

 

发现:并发开启五个客户端,服务端同一时间唯有一个例外的pid,干掉八个客户端,其余贰个客户端才会进入,被贰个进度之一处理

 

  回掉函数:

亟需回调函数的意况:进度池中其他3个职分一旦处理完了,就及时告诉主进度:我好了额,你能够拍卖作者的结果了。主进度则调用叁个函数去处理该结果,该函数即回调函数

我们能够把耗费时间间(阻塞)的职分放到过程池中,然后钦命回调函数(主进度负责执行),那样主进度在实践回调函数时就省去了I/O的经过,直接获得的是职务的结果。

from multiprocessing import Pool
import requests
import json
import os

def get_page(url):
    print('<进程%s> get %s' %(os.getpid(),url))
    respone=requests.get(url)
    if respone.status_code == 200:
        return {'url':url,'text':respone.text}

def pasrse_page(res):
    print('<进程%s> parse %s' %(os.getpid(),res['url']))
    parse_res='url:<%s> size:[%s]\n' %(res['url'],len(res['text']))
    with open('db.txt','a') as f:
        f.write(parse_res)


if __name__ == '__main__':
    urls=[
        'https://www.baidu.com',
        'https://www.python.org',
        'https://www.openstack.org',
        'https://help.github.com/',
        'http://www.sina.com.cn/'
    ]

    p=Pool(3)
    res_l=[]
    for url in urls:
        res=p.apply_async(get_page,args=(url,),callback=pasrse_page)
        res_l.append(res)

    p.close()
    p.join()
    print([res.get() for res in res_l]) #拿到的是get_page的结果,其实完全没必要拿该结果,该结果已经传给回调函数处理了

'''
打印结果:
<进程3388> get https://www.baidu.com
<进程3389> get https://www.python.org
<进程3390> get https://www.openstack.org
<进程3388> get https://help.github.com/
<进程3387> parse https://www.baidu.com
<进程3389> get http://www.sina.com.cn/
<进程3387> parse https://www.python.org
<进程3387> parse https://help.github.com/
<进程3387> parse http://www.sina.com.cn/
<进程3387> parse https://www.openstack.org
[{'url': 'https://www.baidu.com', 'text': '<!DOCTYPE html>\r\n...',...}]
'''

爬虫案例

from multiprocessing import Pool
import time,random
import requests
import re

def get_page(url,pattern):
    response=requests.get(url)
    if response.status_code == 200:
        return (response.text,pattern)

def parse_page(info):
    page_content,pattern=info
    res=re.findall(pattern,page_content)
    for item in res:
        dic={
            'index':item[0],
            'title':item[1],
            'actor':item[2].strip()[3:],
            'time':item[3][5:],
            'score':item[4]+item[5]

        }
        print(dic)
if __name__ == '__main__':
    pattern1=re.compile(r'<dd>.*?board-index.*?>(\d+)<.*?title="(.*?)".*?star.*?>(.*?)<.*?releasetime.*?>(.*?)<.*?integer.*?>(.*?)<.*?fraction.*?>(.*?)<',re.S)

    url_dic={
        'http://maoyan.com/board/7':pattern1,
    }

    p=Pool()
    res_l=[]
    for url,pattern in url_dic.items():
        res=p.apply_async(get_page,args=(url,pattern),callback=parse_page)
        res_l.append(res)

    for i in res_l:
        i.get()

    # res=requests.get('http://maoyan.com/board/7')
    # print(re.findall(pattern,res.text))

假如在主进程中等待历程池中具有职分都进行完成后,再统一处理结果,则无需回调函数

from multiprocessing import Pool
import time,random,os

def work(n):
    time.sleep(1)
    return n**2
if __name__ == '__main__':
    p=Pool()

    res_l=[]
    for i in range(10):
        res=p.apply_async(work,args=(i,))
        res_l.append(res)

    p.close()
    p.join() #等待进程池中所有进程执行完毕

    nums=[]
    for res in res_l:
        nums.append(res.get()) #拿到所有结果
    print(nums) #主进程拿到所有的处理结果,可以在主进程中进行统一进行处理

进程池的别样达成方式:https://docs.python.org/dev/library/concurrent.futures.html

 

Coding 地址HanKin2017

一 multiprocessing模块介绍:

python中的十六线程不能选拔多核优势,假诺想要丰盛地运用多核CPU的财富(os.cpu_count()查看),在python中多数动静需求使用多进度。Python提供了multiprocessing。
   
multiprocessing模块用来开启子进度,并在子进程中实践大家定制的职务(比如函数),该模块与四线程模块threading的编制程序接口类似。

  multiprocessing模块的作用多多:协助子进度、通讯和共享数据、执行不一方式的同台,提供了Process、Queue、Pipe、Lock等零件。

   
要求再一次强调的某个是:与线程分歧,进度没有其余共享状态,进度修改的多寡,改动仅限于该进程内。

 

学号后3位: 267

七 管道

经过间通讯(IPC)格局二:管道(不引进应用,领悟即可)

 

#创建管道的类:
Pipe([duplex]):在进程之间创建一条管道,并返回元组(conn1,conn2),其中conn1,conn2表示管道两端的连接对象,强调一点:必须在产生Process对象之前产生管道
#参数介绍:
dumplex:默认管道是全双工的,如果将duplex射成False,conn1只能用于接收,conn2只能用于发送。
#主要方法:
    conn1.recv():接收conn2.send(obj)发送的对象。如果没有消息可接收,recv方法会一直阻塞。如果连接的另外一端已经关闭,那么recv方法会抛出EOFError。
    conn1.send(obj):通过连接发送对象。obj是与序列化兼容的任意对象
 #其他方法:
conn1.close():关闭连接。如果conn1被垃圾回收,将自动调用此方法
conn1.fileno():返回连接使用的整数文件描述符
conn1.poll([timeout]):如果连接上的数据可用,返回True。timeout指定等待的最长时限。如果省略此参数,方法将立即返回结果。如果将timeout射成None,操作将无限期地等待数据到达。

conn1.recv_bytes([maxlength]):接收c.send_bytes()方法发送的一条完整的字节消息。maxlength指定要接收的最大字节数。如果进入的消息,超过了这个最大值,将引发IOError异常,并且在连接上无法进行进一步读取。如果连接的另外一端已经关闭,再也不存在任何数据,将引发EOFError异常。
conn.send_bytes(buffer [, offset [, size]]):通过连接发送字节数据缓冲区,buffer是支持缓冲区接口的任意对象,offset是缓冲区中的字节偏移量,而size是要发送字节数。结果数据以单条消息的形式发出,然后调用c.recv_bytes()函数进行接收    

conn1.recv_bytes_into(buffer [, offset]):接收一条完整的字节消息,并把它保存在buffer对象中,该对象支持可写入的缓冲区接口(即bytearray对象或类似的对象)。offset指定缓冲区中放置消息处的字节位移。返回值是收到的字节数。如果消息长度大于可用的缓冲区空间,将引发BufferTooShort异常。

介绍

 

基于管道实现进程间通信(与队列的方式是类似的,队列就是管道加锁实现的)

from multiprocessing import Process,Pipe

import time,os
def consumer(p,name):
    left,right=p
    left.close()
    while True:
        try:
            baozi=right.recv()
            print('%s 收到包子:%s' %(name,baozi))
        except EOFError:
            right.close()
            break
def producer(seq,p):
    left,right=p
    right.close()
    for i in seq:
        left.send(i)
        # time.sleep(1)
    else:
        left.close()
if __name__ == '__main__':
    left,right=Pipe()

    c1=Process(target=consumer,args=((left,right),'c1'))
    c1.start()


    seq=(i for i in range(10))
    producer(seq,(left,right))

    right.close()
    left.close()

    c1.join()
    print('主进程')

小心:生产者和顾客都尚未选取管道的某些端点,就活该将其倒闭,如在劳动者中关闭管道的右端,在消费者中关闭管道的左端。借使忘记执行那一个步骤,程序只怕再消费者中的recv()操作上挂起。管道是由操作系统实行引用计数的,必须在具有进程中关闭管道后才能生产EOFError万分。由此在劳动者中关闭管道不会有别的功用,付费消费者中也关门了同样的管道端点。

 

管道可以用于双向通信,利用通常在客户端/服务器中使用的请求/响应模型或远程过程调用,就可以使用管道编写与进程交互的程序

from multiprocessing import Process,Pipe

import time,os
def adder(p,name):
    server,client=p
    client.close()
    while True:
        try:
            x,y=server.recv()
        except EOFError:
            server.close()
            break
        res=x+y
        server.send(res)
    print('server done')
if __name__ == '__main__':
    server,client=Pipe()

    c1=Process(target=adder,args=((server,client),'c1'))
    c1.start()

    server.close()

    client.send((10,20))
    print(client.recv())
    client.close()

    c1.join()
    print('主进程')
#注意:send()和recv()方法使用pickle模块对对象进行序列化。

 

1.您对那门课的愿意是怎样?你打算平均每一周拿出些许个小时用在那门课上?你愿意为了叁个您感兴趣的项目、或获得实战锤炼而付出愈多时间和活力(包蕴熬夜)吗?(必答)

  作者期待在那门课上确实学到知识,提升协调的微处理器技能水平,作者愿意理论知识少点,多点实施。作者打算平均每一周拿出半天的岁月用在那门课上。对于感兴趣的花色笔者会付出更加多日子和生机的,偶尔熬夜勉强尚可,不是专门愿意。

十 事件(了解)

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

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

clear:将“Flag”设置为False
set:将“Flag”设置为True


#_*_coding:utf-8_*_
#!/usr/bin/env python

from multiprocessing import Process,Event
import time,random

def car(e,n):
    while True:
        if not e.is_set(): #Flase
            print('\033[31m红灯亮\033[0m,car%s等着' %n)
            e.wait()
            print('\033[32m车%s 看见绿灯亮了\033[0m' %n)
            time.sleep(random.randint(3,6))
            if not e.is_set():
                continue
            print('走你,car', n)
            break

def police_car(e,n):
    while True:
        if not e.is_set():
            print('\033[31m红灯亮\033[0m,car%s等着' % n)
            e.wait(1)
            print('灯的是%s,警车走了,car %s' %(e.is_set(),n))
            break

def traffic_lights(e,inverval):
    while True:
        time.sleep(inverval)
        if e.is_set():
            e.clear() #e.is_set() ---->False
        else:
            e.set()

if __name__ == '__main__':
    e=Event()
    # for i in range(10):
    #     p=Process(target=car,args=(e,i,))
    #     p.start()

    for i in range(5):
        p = Process(target=police_car, args=(e, i,))
        p.start()
    t=Process(target=traffic_lights,args=(e,10))
    t.start()

    print('============》')

Event(同线程一样)

 

其三部分:未来陈设

七 进度的层次结构

  无论UNIX还是windows,进度只有一个父进程,不一致的是:

  1.
在UNIX中拥有的进程,都是以init进度为根,组成树形结构。父子进程共同组成三个经过组,那样,当从键盘发出1个信号时,该信号被送给当前与键盘相关的历程组中的拥有成员。

  2.
在windows中,没有经过层次的概念,全部的历程都是地位平等的,唯一类似于经过层次的授意,是在创造进度时,父进度取得1个特地的令牌(名为句柄),该句柄能够用来控制子进度,不过父进度有权把该句柄传给别的子进程,那样就从不层次了。

1.对于你今后在IT行业的升高,你有何的期望大概今后想从事什么的行事?你准备怎么样来布置你技术道路,职业道路和社会征程?(必答)

  作者的希望是结业后能找一份满意的干活,笔者今后跟导师做社交互联网数据处理和挖掘,今后打算从事数码处理地点的做事。熟谙数据挖掘领域知识,学习运用数据挖掘工具,学习算法知识。培育本身大旨编制程序、思维、数据处理能力。努力学习,努力进步本身的微处理器技能水平,认真对待自个儿接触的品种,抓住每1个犯难的时机,时刻警醒自身,多和身边的大牛接触和交换。与此同时,多量观望国内外优质资料,最终尝试着自身写策划案。

九 进度并发的落到实处(明白)

  进度并发的落到实处在于,硬件中断二个正在运行的进度,把那儿进度运维的保有情况保存下去,为此,操作系统维护一张表格,即进程表(process
table),各样进度占用叁个历程表项(这么些表项也叫做进度控制块)

王者荣耀 2

  该表存放了经过景况的首要性音讯:程序计数器、堆栈指针、内部存款和储蓄器分配意况、全数打开文件的情况、帐号和调度音信,以及其余在进程由运维态转为就绪态或不通态时,必须保留的音信,从而有限扶助该进度在重新运转时,就像没有被暂停过千篇一律。

2.迄今截至,你写了略微代码,描述您做的最复杂的软件项目/作业。(必答)

  小编直接记得大学一年级时计算机导论老师说过的一句话:代码改变世界。小编就全力以赴的敲啊敲啊,大学一年级接触c和c++语言,大二到位了母校的科学和技术术创新新基金项目,大三临场了4个月的算法竞技教练和部分零星的竞技,代码也没怎么总括过,大致两千0多行呢(本人并没想象中的那么强劲,贪玩,自觉性低)。做的最复杂的软件项目大致正是在场全校的时间限制一年的科创基金项目比赛,做了一个基于二维码的装置巡检系统app。团队一起是几个人,到了结项的末梢四个月,大家也没怎么当回事,都没怎么兴趣学习安卓做app,都是画饼充饥,最后app的任务交给了自家壹人,自己在自学中学到二个零部件模块就往app加进去,最后勉强做了3个app躯壳(界面),里面超越四分之二有血有肉的法力尚未落到实处。

六 队列(推荐应用)

  
进程互相之间相互隔断,要贯彻进度间通讯(IPC),multiprocessing模块帮衬三种方式:队列和管道,那二种艺术都以行使信息传递的

 创设队列的类(底层正是以管道和锁定的法门完毕)

1 Queue([maxsize]):创建共享的进程队列,Queue是多进程安全的队列,可以使用Queue实现多进程之间的数据传递。 

    参数介绍:

1 maxsize是队列中允许最大项数,省略则无大小限制。    

  格局介绍:

    首要措施:

q.put方法用以插入数据到队列中,put方法还有两个可选参数:blocked和timeout。如果blocked为True(默认值),并且timeout为正值,该方法会阻塞timeout指定的时间,直到该队列有剩余的空间。如果超时,会抛出Queue.Full异常。如果blocked为False,但该Queue已满,会立即抛出Queue.Full异常。
q.get方法可以从队列读取并且删除一个元素。同样,get方法有两个可选参数:blocked和timeout。如果blocked为True(默认值),并且timeout为正值,那么在等待时间内没有取到任何元素,会抛出Queue.Empty异常。如果blocked为False,有两种情况存在,如果Queue有一个值可用,则立即返回该值,否则,如果队列为空,则立即抛出Queue.Empty异常.

q.get_nowait():同q.get(False)
q.put_nowait():同q.put(False)

q.empty():调用此方法时q为空则返回True,该结果不可靠,比如在返回True的过程中,如果队列中又加入了项目。
q.full():调用此方法时q已满则返回True,该结果不可靠,比如在返回True的过程中,如果队列中的项目被取走。
q.qsize():返回队列中目前项目的正确数量,结果也不可靠,理由同q.empty()和q.full()一样

任何格局(理解):

1 q.cancel_join_thread():不会在进程退出时自动连接后台线程。可以防止join_thread()方法阻塞
2 q.close():关闭队列,防止队列中加入更多数据。调用此方法,后台线程将继续写入那些已经入队列但尚未写入的数据,但将在此方法完成时马上关闭。如果q被垃圾收集,将调用此方法。关闭队列不会在队列使用者中产生任何类型的数据结束信号或异常。例如,如果某个使用者正在被阻塞在get()操作上,关闭生产者中的队列不会导致get()方法返回错误。
3 q.join_thread():连接队列的后台线程。此方法用于在调用q.close()方法之后,等待所有队列项被消耗。默认情况下,此方法由不是q的原始创建者的所有进程调用。调用q.cancel_join_thread方法可以禁止这种行为

  应用:

'''
multiprocessing模块支持进程间通信的两种主要形式:管道和队列
都是基于消息传递实现的,但是队列接口
'''

from multiprocessing import Process,Queue
import time
q=Queue(3)


#put ,get ,put_nowait,get_nowait,full,empty
q.put(3)
q.put(3)
q.put(3)
print(q.full()) #满了

print(q.get())
print(q.get())
print(q.get())
print(q.empty()) #空了

劳动者消费者模型

在产出编制程序中应用生产者和买主形式能够缓解大多数出现难题。该方式通过平衡生产线程和消费线程的办事能力来提升程序的完好处理多少的进程。

    为啥要利用生产者和买主方式

在线程世界里,生产者便是生产数据的线程,消费者正是成本数量的线程。在二十八线程开发个中,假使劳动者处理速度相当的慢,而消费者处理速度极慢,那么生产者就亟须等待顾客处理完,才能继续生产数据。同样的道理,倘诺顾客的拍卖能力超越生产者,那么消费者就非得待产者。为了化解那些难点于是引入了劳动者和消费者格局。

    什么是劳动者消费者形式

生产者消费者情势是经过二个容器来缓解劳动者和顾客的强耦合难题。生产者和顾客互相之间不直接通信,而因而阻塞队列来拓展报纸发表,所以生产者生产完数据未来并非等待买主处理,直接扔给卡住队列,消费者不找生产者要多少,而是径直从绿灯队列里取,阻塞队列就一定于三个缓冲区,平衡了劳动者和顾客的拍卖能力。

故事队列完成生产者消费者模型

from multiprocessing import Process,Queue
import time,random,os
def consumer(q):
    while True:
        res=q.get()
        time.sleep(random.randint(1,3))
        print('\033[45m%s 吃 %s\033[0m' %(os.getpid(),res))

def producer(q):
    for i in range(10):
        time.sleep(random.randint(1,3))
        res='包子%s' %i
        q.put(res)
        print('\033[44m%s 生产了 %s\033[0m' %(os.getpid(),res))

if __name__ == '__main__':
    q=Queue()
    #生产者们:即厨师们
    p1=Process(target=producer,args=(q,))

    #消费者们:即吃货们
    c1=Process(target=consumer,args=(q,))

    #开始
    p1.start()
    c1.start()
    print('主')

这时候的标题是主进度永远不会甘休,原因是:生产者p在生养完后就与世长辞了,可是消费者c在取空了q之后,则直接处于死循环中且卡在q.get()这一步。

解决措施唯有是让劳动者在生育完毕后,往队列中再发1个扫尾信号,那样顾客在吸收接纳到完工信号后就足以break出死循环

 

生产者在生产完毕后发送结束信号None

from multiprocessing import Process,Queue
import time,random,os
def consumer(q):
    while True:
        res=q.get()
        if res is None:break #收到结束信号则结束
        time.sleep(random.randint(1,3))
        print('\033[45m%s 吃 %s\033[0m' %(os.getpid(),res))

def producer(q):
    for i in range(10):
        time.sleep(random.randint(1,3))
        res='包子%s' %i
        q.put(res)
        print('\033[44m%s 生产了 %s\033[0m' %(os.getpid(),res))
    q.put(None) #发送结束信号
if __name__ == '__main__':
    q=Queue()
    #生产者们:即厨师们
    p1=Process(target=producer,args=(q,))

    #消费者们:即吃货们
    c1=Process(target=consumer,args=(q,))

    #开始
    p1.start()
    c1.start()
    print('主')

注意:截至信号None,不肯定要由生产者发,主进程里同样能够发,但主进度要求等生产者停止后才应该发送该信号

主进程在生产者生产完毕后发送结束信号None

from multiprocessing import Process,Queue
import time,random,os
def consumer(q):
    while True:
        res=q.get()
        if res is None:break #收到结束信号则结束
        time.sleep(random.randint(1,3))
        print('\033[45m%s 吃 %s\033[0m' %(os.getpid(),res))

def producer(q):
    for i in range(2):
        time.sleep(random.randint(1,3))
        res='包子%s' %i
        q.put(res)
        print('\033[44m%s 生产了 %s\033[0m' %(os.getpid(),res))

if __name__ == '__main__':
    q=Queue()
    #生产者们:即厨师们
    p1=Process(target=producer,args=(q,))

    #消费者们:即吃货们
    c1=Process(target=consumer,args=(q,))

    #开始
    p1.start()
    c1.start()

    p1.join()
    q.put(None) #发送结束信号
    print('主')

但上述化解措施,在有三个生产者和四个顾客时,我们则必要用1个很low的法子去消除

有几个生产者就需要发送几次结束信号:相当low

from multiprocessing import Process,Queue
import time,random,os
def consumer(q):
    while True:
        res=q.get()
        if res is None:break #收到结束信号则结束
        time.sleep(random.randint(1,3))
        print('\033[45m%s 吃 %s\033[0m' %(os.getpid(),res))

def producer(name,q):
    for i in range(2):
        time.sleep(random.randint(1,3))
        res='%s%s' %(name,i)
        q.put(res)
        print('\033[44m%s 生产了 %s\033[0m' %(os.getpid(),res))



if __name__ == '__main__':
    q=Queue()
    #生产者们:即厨师们
    p1=Process(target=producer,args=('包子',q))
    p2=Process(target=producer,args=('骨头',q))
    p3=Process(target=producer,args=('泔水',q))

    #消费者们:即吃货们
    c1=Process(target=consumer,args=(q,))
    c2=Process(target=consumer,args=(q,))

    #开始
    p1.start()
    p2.start()
    p3.start()
    c1.start()

    p1.join() #必须保证生产者全部生产完毕,才应该发送结束信号
    p2.join()
    p3.join()
    q.put(None) #有几个生产者就应该发送几次结束信号None
    q.put(None) #发送结束信号
    q.put(None) #发送结束信号
    print('主')

 

实在大家的思路无非是发送甘休信号而已,有其它一种队列提供了那种体制

#JoinableQueue([maxsize]):这就像是一个Queue对象,但队列允许项目的使用者通知生成者项目已经被成功处理。通知进程是使用共享的信号和条件变量来实现的。

   #参数介绍:
    maxsize是队列中允许最大项数,省略则无大小限制。    
  #方法介绍:
    JoinableQueue的实例p除了与Queue对象相同的方法之外还具有:
    q.task_done():使用者使用此方法发出信号,表示q.get()的返回项目已经被处理。如果调用此方法的次数大于从队列中删除项目的数量,将引发ValueError异常
    q.join():生产者调用此方法进行阻塞,直到队列中所有的项目均被处理。阻塞将持续到队列中的每个项目均调用q.task_done()方法为止

from multiprocessing import Process,JoinableQueue
import time,random,os
def consumer(q):
    while True:
        res=q.get()
        time.sleep(random.randint(1,3))
        print('\033[45m%s 吃 %s\033[0m' %(os.getpid(),res))

        q.task_done() #向q.join()发送一次信号,证明一个数据已经被取走了

def producer(name,q):
    for i in range(10):
        time.sleep(random.randint(1,3))
        res='%s%s' %(name,i)
        q.put(res)
        print('\033[44m%s 生产了 %s\033[0m' %(os.getpid(),res))
    q.join()


if __name__ == '__main__':
    q=JoinableQueue()
    #生产者们:即厨师们
    p1=Process(target=producer,args=('包子',q))
    p2=Process(target=producer,args=('骨头',q))
    p3=Process(target=producer,args=('泔水',q))

    #消费者们:即吃货们
    c1=Process(target=consumer,args=(q,))
    c2=Process(target=consumer,args=(q,))
    c1.daemon=True
    c2.daemon=True

    #开始
    p_l=[p1,p2,p3,c1,c2]
    for p in p_l:
        p.start()

    p1.join()
    p2.join()
    p3.join()
    print('主') 

    #主进程等--->p1,p2,p3等---->c1,c2
    #p1,p2,p3结束了,证明c1,c2肯定全都收完了p1,p2,p3发到队列的数据
    #因而c1,c2也没有存在的价值了,应该随着主进程的结束而结束,所以设置成守护进程

1.您怎么选拔计算机专业?你觉得你的条件如何?和那个博主比吧?(必答)

  笔者高中毕业后填写志愿时,对选什么样正儿八经很糊涂,不知情本身适合做如何。小编回忆当时是大伯向自个儿引进多少个今后看好行业:助教、医务卫生人士、总括机。作者高等学校统招考试分数不是很高,笔者就废弃了亟需高分的医师规范。作者口才不是很好,交际能力一般,相比较内向,就没咋考虑教员行业了。首先本身选拔的是全校,我纪念第③自觉填的是通讯工程(总括机方向,未来提高好),第②志愿选的是自动化(高校强势专业),第贰自觉自愿选的是地勘衡量技术(好奇,高校强专业),第五自觉选项的是电脑科学与技术(随便选的,有电脑四个字),前面包车型大巴自觉记不知情了。笔者前边多少个自愿都没录取上,自身稀里糊涂的就到来了电脑的社会风气-计算机科学与技术(当时统统不精晓那规范是干啥的)。作者对当下的选取感到很幸运,大学四年后自身发现自身依旧适合总计机方面喜欢电脑专业,没有被自动化和地质勘察技术那样的正经录取,通讯工程小编不是很明白(信号处理、模电不是自我快乐的课程,物理不是本身的一艺之长),作者爱好编制程序,喜欢专研技术,喜欢看看大牛做出来的很cool的事物。

  报考硕士复习大约一年,在这一年中山大学多并未花时间去撸代码,考完研后,发现从前学习的事物基本上忘记了,但是在此之前学习的东西未来重新整建起来相比较便于一些,有了自然的电脑基础,看了这么多博主的博文,讲的都以1个二个励志的遗闻,作者觉得他们能到位的,笔者也能形成,作者后天的处理器水平自然没有那个博主,但万一本身像他们那么努力,笔者相信本人会拉近和博主之间的离开的。

六 进度的终止(精晓)

  1.
例行退出(自愿,如用户点击交互式页面包车型客车叉号,或程序执行完毕调用发起系统调用正常退出,在linux中用exit,在windows中用ExitProcess)

  2. 弄错退出(自愿,python a.py中a.py不设有)

  3.
严重错误(非自愿,执行违法命令,如引用不存在的内部存款和储蓄器,1/0等,能够捕捉万分,try…except…)

  4. 被别的进度杀死(非自愿,如kill -9)

 

第1片段:在计算机系里学习

八 进度的意况

  tail -f access.log |grep ‘404’

  执行程序tail,开启3个子进度,执行顺序grep,开启别的三个子经过,三个进程之间基于管道’|’通信,将tail的结果作为grep的输入。

  进度grep在等候输入(即I/O)时的气象叫做阻塞,此时grep命令都不可能运维

  其实在二种情景下会造成叁个历程在逻辑上不能够运维,

  1.
历程挂起是小编原因,境遇I/O阻塞,便要让出CPU让别的进度去执行,那样有限协助CPU一向在工作

  2.
与经过毫无干系,是操作系统层面,只怕会因为多个经过占用时间过多,只怕优先级等原因,而调用其余的进度去行使CPU。

  由此二个经过由三种情景

王者荣耀 3

第4有些:课程期望

五 进度同步(锁)

进度之间数据不共享,不过共享同一套文件系统,所以访问同三个文本,或同一个打字与印刷终端,是从未难点的,

竞争带来的结果正是乱套,怎么样支配,正是加锁处理

part1:三个经过共享同一打字与印刷终端

并发运行,效率高,但竞争同一打印终端,带来了打印错乱

#并发运行,效率高,但竞争同一打印终端,带来了打印错乱
from multiprocessing import Process
import os,time
def work():
    print('%s is running' %os.getpid())
    time.sleep(2)
    print('%s is done' %os.getpid())

if __name__ == '__main__':
    for i in range(3):
        p=Process(target=work)
        p.start()

加锁:由并发变成了串行,牺牲了运行效率,但避免了竞争

#由并发变成了串行,牺牲了运行效率,但避免了竞争
from multiprocessing import Process,Lock
import os,time
def work(lock):
    lock.acquire()
    print('%s is running' %os.getpid())
    time.sleep(2)
    print('%s is done' %os.getpid())
    lock.release()
if __name__ == '__main__':
    lock=Lock()
    for i in range(3):
        p=Process(target=work,args=(lock,))
        p.start()

part2:三个进程共享同一文件

文本当数据库,模拟抢票

并发运行,效率高,但竞争写同一文件,数据写入错乱

#文件db的内容为:{"count":1}
#注意一定要用双引号,不然json无法识别
from multiprocessing import Process,Lock
import time,json,random
def search():
    dic=json.load(open('db.txt'))
    print('\033[43m剩余票数%s\033[0m' %dic['count'])

def get():
    dic=json.load(open('db.txt'))
    time.sleep(0.1) #模拟读数据的网络延迟
    if dic['count'] >0:
        dic['count']-=1
        time.sleep(0.2) #模拟写数据的网络延迟
        json.dump(dic,open('db.txt','w'))
        print('\033[43m购票成功\033[0m')

def task(lock):
    search()
    get()
if __name__ == '__main__':
    lock=Lock()
    for i in range(100): #模拟并发100个客户端抢票
        p=Process(target=task,args=(lock,))
        p.start()

加锁:购票行为由并发变成了串行,牺牲了运行效率,但保证了数据安全

#文件db的内容为:{"count":1}
#注意一定要用双引号,不然json无法识别
from multiprocessing import Process,Lock
import time,json,random
def search():
    dic=json.load(open('db.txt'))
    print('\033[43m剩余票数%s\033[0m' %dic['count'])

def get():
    dic=json.load(open('db.txt'))
    time.sleep(0.1) #模拟读数据的网络延迟
    if dic['count'] >0:
        dic['count']-=1
        time.sleep(0.2) #模拟写数据的网络延迟
        json.dump(dic,open('db.txt','w'))
        print('\033[43m购票成功\033[0m')

def task(lock):
    search()
    lock.acquire()
    get()
    lock.release()
if __name__ == '__main__':
    lock=Lock()
    for i in range(100): #模拟并发100个客户端抢票
        p=Process(target=task,args=(lock,))
        p.start()

总结:

加锁能够确定保障多少个经过修改同一块数据时,同近来间只好有多个职责可以拓展改动,即串行的改动,没错,速度是慢了,但捐躯了进度却保险了数码安全。
就算如此能够用文件共享数据达成进度间通讯,但难点是:
1.效率低
2.亟需自个儿加锁处理

 

为此mutiprocessing模块为大家提供了基于音信的IPC通讯机制:队列和管道。
1 队列和管道都以将数据存放于内部存款和储蓄器中
2 队列又是依照(管道+锁)达成的,能够让我们从长短不一的锁难点中摆脱出来,
我们应当尽量防止使用共享数据,尽恐怕使用音讯传递和队列,避免处理丝丝缕缕的同台和锁难点,而且在进程数目扩张时,往往能够获取更好的可获展性。

 

3.科班出身和南开青鸟有哪些分化?

  科班出身的偏于基础知识和辩护,基本功扎实,南开青鸟应该体贴实践和品种。

二 Process类的介绍

 开创进度的类

Process([group [, target [, name [, args [, kwargs]]]]]),由该类实例化得到的对象,表示一个子进程中的任务(尚未启动)

强调:
1. 需要使用关键字的方式来指定参数
2. args指定的为传给target函数的位置参数,是一个元组形式,必须有逗号

  参数介绍:

group参数未使用,值始终为None

target表示调用对象,即子进度要履行的义务

args表示调用对象的地方参数元组,args=(1,2,’egon’,)

kwargs表示调用对象的字典,kwargs={‘name’:’egon’,’age’:18}

name为子进程的称谓

 

 方法介绍:

p.start():运维进度,并调用该子进程中的p.run()
p.run():进程运转时运转的方式,就是它去调用target钦定的函数,我们自定义类的类中必然要达成该方法

p.terminate():强制截止进度p,不会进展别的清理操作,如若p创立了子进度,该子进度就成了僵尸进度,使用该形式需求特地小心那种情况。倘诺p还保存了2个锁那么也将不会被放飞,进而导致死锁
p.is_alive():假若p还是运转,再次来到True

p.join([timeout]):主线程等待p终止(强调:是主线程处于等的意况,而p是处于运行的情景)。timeout是可选的晚点时间,须求强调的是,p.join只好join住start开启的长河,而无法join住run开启的进度

个性介绍:

1 p.daemon:默认值为False,如果设为True,代表p为后台运行的守护进程,当p的父进程终止时,p也随之终止,并且设定为True后,p不能创建自己的新进程,必须在p.start()之前设置
2 
3 p.name:进程的名称
4 
5 p.pid:进程的pid
6 
7 p.exitcode:进程在运行时为None、如果为–N,表示被信号N结束(了解即可)
8 
9 p.authkey:进程的身份验证键,默认是由os.urandom()随机生成的32字符的字符串。这个键的用途是为涉及网络连接的底层进程间通信提供安全性,这类连接只有在具有相同的身份验证键时才能成功(了解即可)

一 什么是进程

    进程:正在进展的1个历程恐怕说一个职责。而背负实施职责则是cpu。

    举例(单核+多道,完毕四个经过的出现执行):

   
egon在3个时间段内有多如牛毛职务要做:python备课的天职,写书的职责,交女朋友的职分,王者荣耀上分的任务,  

   
但egon同权且刻只好做3个职责(cpu同一时间只好干3个活),怎么着才能玩出多少个义务并发执行的效用?

   
egon备一会课,再去跟李治的女对象聊聊天,再去打一会王者荣耀….这就保障了各类职责都在展开中.

五 进度的创导(精晓)

  但凡是硬件,都亟待有操作系统去管理,只要有操作系统,就有进度的定义,就供给有开创进度的点子,一些操作系统只为一个应用程序设计,比如微波炉中的控制器,一旦运转微波炉,全体的长河都早就存在。

  而对此通用系统(跑很多应用程序),供给有系统运行进度中开创或撤消进度的力量,首要分为4中形式创设新的进程

  1.
系统初阶化(查看进度linux中用ps命令,windows中用职务管理器,前台进度负责与用户交互,后台运转的经过与用户毫不相关,运营在后台并且只在急需时才提示的长河,称为守护进程,如电子邮件、web页面、新闻、打印)

  2.
3个经过在运维进度中打开了子进度(如nginx开启多进程,os.fork,subprocess.Popen等)

  3. 用户的交互式请求,而创办1个新进度(如用户双击沙尘卷风影音)

  4. 四个批处理作业的先导化(只在大型机的批处理种类中选择)

  

  无论哪个种类,新进程的创办都以由三个早就存在的经过执行了一个用以成立进度的种类调用而创建的:

  1.
在UNIX中该连串调用是:fork,fork会创造3个与父进度一模一样的副本,二者有一样的储存影象、同样的条件字符串和平等的打开文件(在shell解释器进度中,执行3个发令就会创制二个子历程)

  2.
在windows中该连串调用是:CreateProcess,CreateProcess既处理进度的创始,也负担把正确的程序装入新进程。

 

  关于创造的子进度,UNIX和windows

  1.同等的是:进程创设后,父进度和子进度有独家区别的地方空间(多道技术要求物理层面实现进度之间内部存款和储蓄器的隔绝),任何贰个进度的在其地方空间中的修改都不会影响到其它贰个历程。

  2.见仁见智的是:在UNIX中,子进度的初阶地址空间是父进度的多个副本,提示:子过程和父进度是足以有只读的共享内部存款和储蓄器区的。可是对于windows系统来说,从一初叶父进度与子进程的地址空间就是区别的。

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*
*
Website