网络传输进阶篇----并发

Posted takafter

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络传输进阶篇----并发相关的知识,希望对你有一定的参考价值。

一、并发是什么

? 较为通俗的去理解并发这件事情本身,这就要牵扯到计算机的发展。我再这笼统的概括,在网上能够找到十分详细的计算机发展史。

? https://blog.csdn.net/zzwu/article/details/77792789——请参见大佬的文章

? 在计算及一开始,工业生产能力并不能实现如今的多核的生产条件,当然也包括 那个时候并没有相关的理论。所以,在那个时候运行计算机那是相当的麻烦,很多人只能排着队等着来。这时候,优秀的程序猿就思考着为什么不能在计算机计算他人的内容的时候,接着运行别人的呢。因此他们就想到了并发——同时运行多个程序在一个处理器上。因为当程序在运行的时候,除开一些较为复杂的计算下,处理器占用较为多之外,很多时候都是进行的文件的读写 也就是 I/O 功能,这只占用计算机处理器的一小部分,大多数的部分就只能白白浪费。毕竟,效率就是生产力啊!!

? 引用百度的正规称呼——“并发,在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行。”——应用自百度

 

二、进程——基本内容

1.什么是进程

? 正在进行的一个过程或者说一个任务。

2.进程和程序

? 程序是一对代码,进程则是程序的运行过程。

3.并发和并行

? 并发是看起来是同时进行了,但实际是处理器在多个任务之间的高速来回移动。

? 并行是真正的同时运行,但条件是得有多个CPU。因为一个CPU只能执行一个任务。

?

三、进程——multiprocessing模块

1.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还保存了一个锁那么也将不会被释放,进而导致死锁
p.is_alive():如果p仍然运行,返回True
?
p.join([timeout]):主线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状态)。timeout是可选的超时时间。

? **属性介绍**

p.daemon:默认值为False,如果设为True,代表p为后台运行的守护进程,当p的父进程终止时,p也随之终止,并且设定为True后,p不能创建自己的新进程,必须在p.start()之前设置
?
p.name:进程的名称
?
p.pid:进程的pid

 

2.Process类的使用

? **windows的Process必须在 if name == ‘main‘:下**

?

? **创建方式一**

#!/usr/bin/python
# -*- coding:utf-8 -*-
from multiprocessing import Process
?
?
def people(name, sex):
   print("%s is %s" % (name, sex))
?
?
if __name__ == ‘__main__‘:
   p1 = Process(target=people, args=("张三", "man",))
   p2 = Process(target=people, args=("李四", "man",))
   p3 = Process(target=people, args=("狗蛋", "female",))
?
   p1.start()
   p2.start()
   p3.start()
?
   print("主要程序")

 

 

? **方式二**

#!/usr/bin/python
# -*- coding:utf-8 -*-
from multiprocessing import Process
?
?
class People(Process):
   def __init__(self, name, sex):
       super().__init__()
       self.name = name
       self.sex = sex
?
   def run(self):
       print("%s is %s" % (self.name, self.sex))
?
?
if __name__ == ‘__main__‘:
   p1 = People("张三", "man")
   p2 = People("李四", "man")
   p3 = People("狗蛋", "female")
?
   p1.start()
   p2.start()
   p3.start()
?
   print("主要程序")

3.joint

? 通过上面的创建,能发现的一个问题就是:在主进程都已经结束完成后,子进程并没有完成。因为我们看到的代码只是向处理器发出了一个信号,但是实际上并没有运行。而主进程并不需要进行进程方面的创建,直接就运行了。

? 那么,主进程能够等着子进程运行完成之后,自己再进行吗?

? 答案显然是可以的。

 

? 只需要在主进程之前加上joint()就可以。

? joint就是认为的对主程序进行阻塞,只有joint所对应的子进程运行完成后,主进程才能运行。

#!/usr/bin/python
# -*- coding:utf-8 -*-
from multiprocessing import Process
?
?
def people(name, sex):
   print("%s is %s" % (name, sex))
?
?
if __name__ == ‘__main__‘:
   p1 = Process(target=people, args=("张三", "man",))
   p2 = Process(target=people, args=("李四", "man",))
   p3 = Process(target=people, args=("狗蛋", "female",))
?
   p1.start()
   p2.start()
   p3.start()
?
   p1.join()
   p2.join()
   p3.join()
?
   print("主要程序")
   
   #注意:有多少个对象,就要有对应的join

 

? **注意:加上joint的进程并不是串行**

? 因为joint阻塞了主进程,但是子进程还是并发的在进行着。和串行一个一个运行还是有着本质的不用的。

 

? **对象其他属性或方法**

? **terminal 与 is——alive**

#!/usr/bin/python
# -*- coding:utf-8 -*-
from multiprocessing import Process
?
?
def people(name, sex):
   print("%s is %s" % (name, sex))
?
?
if __name__ == ‘__main__‘:
   p1 = Process(target=people, args=("张三", "man",))
   p1.start()    
   
   p1.terminate()
   print(p1.is_alive())
   
   print("主要程序")

运行后的结果:

True
主要程序

 

? **name 与 pid**

?

#!/usr/bin/python
# -*- coding:utf-8 -*-
from multiprocessing import Process
?
?
def people(name, sex):
   print("%s is %s" % (name, sex))
?
?
if __name__ == ‘__main__‘:
   p1 = Process(target=people, args=("张三", "man",))
   p1.start()
?
   print(p1.name, p1.pid)
?
   print("主要程序")

运行结果:

Process-1 17072
主要程序
张三 is man

 

4.守护进程

? 守护进程就是伴随主进程左右的子进程,在主进程结束之前,自己绝对不会结束的子进程。

? **强调:一、主进程结束就终止;二、守护进程内不能开子进程,否则抛出异常**

?

#!/usr/bin/python
# -*- coding:utf-8 -*-
from multiprocessing import Process
?
?
def people(name, sex):
   print("%s is %s" % (name, sex))
?
?
if __name__ == ‘__main__‘:
   p1 = Process(target=people, args=("张三", "man",))
?
   p1.daemon = True
   p1.start()
?
   print("主进程")
?
# daemon必须要在start上面

 

5.互斥锁

? 并发虽然解决了效率的问题,但是也带来了一个问题就是容易带来错乱。

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()

运行结果:

第一次结果
19428 is running
19364 is running
18716 is running
19428 is done
18716 is done
19364 is done
?
?
第二次结果
28012 is running
7920 is running
23080 is running
7920 is done
28012 is done
23080 is done

? 互斥锁将解决这个问题。

? 互斥锁就是一个门卫,谁抢到谁先进去,剩下的人在下面等着。

? 虽然保证了质量,但是效率也就不存在了。互斥锁将本来的并发变成了串行。

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()
   
#加上锁acquire之后一定要在最后release 否则下面的数据根本进不去

 

? **互斥锁与joint**

? joint是一个一个的运行,即上一个结束,下一个进去

? 互斥锁是多个一起去抢,谁抢到谁运行。然后再抢,在运行。如此循环往复。

? 即,join是将一个任务整体串行,而互斥锁的好处则是可以将一个任务中的某一段代码串行,比如只让task函数中的get任务串行

def task(name,):
   search(name) # 并发执行
?
   lock.acquire()
   get(name) #串行执行
   lock.release()

? 互斥锁中可以有部分是并发执行,而joint无法做到

 

6.队列

? **重要**

#队列的创建
Queue([maxsize]):创建共享的进程队列,Queue是多进程安全的队列,可以使用Queue实现多进程之间的数据传递。
   
#!/usr/bin/python
# -*- coding:utf-8 -*-
from multiprocessing import Process
import queue
?
?
def people(name, sex):
   print("%s is %s" % (name, sex))
?
?
if __name__ == ‘__main__‘:
   p1 = Process(target=people, args=("张三", "man",))
   p2 = Process(target=people, args=("李四", "man",))
   p3 = Process(target=people, args=("狗蛋", "female",))
?
   q = queue.Queue(2)
   q.put(p1)
   q.put(p2)
   print(q.full())
?
   p1.start()
   p2.start()
   p3.start()
   
   print(q.get())
   print(q.get())
?
   print(q.empty())
?
   print("主要程序")
   
#如果q.put()和 q.get()查过2 程序会卡住不再运行

 本文知识点引自与http://www.cnblogs.com/linhaifeng/大佬


























































































































































































































以上是关于网络传输进阶篇----并发的主要内容,如果未能解决你的问题,请参考以下文章

并发编程进阶学习篇

Web应用的组件化进阶篇

网络编程进阶及并发编程

Go语言之进阶篇爬百度贴吧并发版

并发和数据库

Python面试重点(进阶篇)