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

一、并发是什么

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

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/大佬

猜你喜欢

转载自www.cnblogs.com/takafter/p/9385924.html