进程,协程

一:进程:进程是操作系统结构的基础;是一个正在执行的程序;计算机中正在运行的程序实例;可以分配给处理器并由处理器执行的一个实体;由单一顺序的执行显示,一个当前状态和一组相关的系统资源所描述的活动单元

1.多进程

由于GIL的存在,python中的多线程其实并不是真正的多线程,如果想要充分地使用多核CPU的资源,在python中大部分情况需要使用多进程。Python提供了非常好用的多进程包multiprocessing,只需要定义一个函数,Python会完成其他所有事情。借助这个包,可以轻松完成从单进程到并发执行的转换。multiprocessing支持子进程、通信和共享数据、执行不同形式的同步,提供了Process、Queue、Pipe、Lock等组件。

  multiprocessing包是Python中的多进程管理包。与threading.Thread类似,它可以利用multiprocessing.Process对象来创建一个进程。该进程可以运行在Python程序内部编写的函数。该Process对象与Thread对象的用法相同,也有start(), run(), join()的方法。此外multiprocessing包中也有Lock/Event/Semaphore/Condition类 (这些对象可以像多线程那样,通过参数传递给各个进程),用以同步进程,其用法与threading包中的同名类一致。所以,multiprocessing的很大一部份与threading使用同一套API,只不过换到了多进程的情境。

但在使用这些共享API的时候,我们要注意以下几点:

在UNIX平台上,当某个进程终结之后,该进程需要被其父进程调用wait,否则进程成为僵尸进程(Zombie)。所以,有必要对每个Process对象调用join()方法 (实际上等同于wait)。对于多线程来说,由于只有一个进程,所以不存在此必要性。
multiprocessing提供了threading包中没有的IPC(比如Pipe和Queue),效率上更高。应优先考虑Pipe和Queue,避免使用Lock/Event/Semaphore/Condition等同步方式 (因为它们占据的不是用户进程的资源)。
多进程应该避免共享资源。在多线程中,我们可以比较容易地共享资源,比如使用全局变量或者传递参数。在多进程情况下,由于每个进程有自己独立的内存空间,以上方法并不合适。此时我们可以通过共享内存和Manager的方法来共享资源。但这样做提高了程序的复杂度,并因为同步的需要而降低了程序的效率。
Process.PID中保存有PID,如果进程还没有start(),则PID为None。

window系统下,需要注意的是要想启动一个子进程,必须加上那句if __name__ == "main",进程相关的要写在这句下面。

来直接看一下代码

from multiprocessing import Process
import time
def f(name):
    time.sleep(1)
    print("hello",name,time.ctime())
if __name__ == "__main__":
    p_list = []
    for i in range(3):
        p = Process(target = f,args = ("alex",))
        p_list.append(p)
        p.start()
    for i in p_list:
        p.join()                #注意这个地方得到join,等到上面的所有执行完以后再执行最后的end
    print("end")结果为:

hello alex Wed Oct 12 16:50:18 2016
hello alex Wed Oct 12 16:50:18 2016
hello alex Wed Oct 12 16:50:18 2016
end

2.类式调用

from multiprocessing import Process
import time

class MyProcess(Process):
    def __init__(self,):
        super(MyProcess,self).__init__()
        #self.name = name
    def run(self):
        time.sleep(1)
        print("hello",self.name,time.ctime())     #此时的self.name 是进程对象下的一个属性,是有名字的,
if __name__ == "__main__":
    p_list =[]
    for i in range(3):
        p = MyProcess()
        p.start()
        p_list.append(p)
    for p in p_list:
        p.join()
    print("end")结果为:

hello MyProcess-1 Wed Oct 12 16:59:27 2016
hello MyProcess-2 Wed Oct 12 16:59:27 2016
hello MyProcess-3 Wed Oct 12 16:59:27 2016
end

3.进程关系(父进程与子进程之间的关系)

from multiprocessing import Process
import os
import time
def info(title):
    print(title)
    print("module name:",__name__)
    print("parent process:",os.getppid())
    print("process id:",os.getpid())
def f(name):
    info("\033[3;1mfunction f\033[0m")
    print("hello",name)

if __name__ == "__main__":
    info("\033[32;1mmain process line\033[0m")
    time.sleep(2)
    p = Process(target = info,args=("bob",))
    p.start()
    p.join()结果为:

main process line
module name: __main__
parent process: 12888
process id: 13432
bob
module name: __mp_main__
parent process: 13432
process id: 13036

二:Process类

构造方法:

Process([group [, target [, name [, args [, kwargs]]]]])

  group: 线程组,目前还没有实现,库引用中提示必须是None;
  target: 要执行的方法;
  name: 进程名;
  args/kwargs: 要传入方法的参数。

实例方法:

  is_alive():返回进程是否在运行。

  join([timeout]):阻塞当前上下文环境的进程程,直到调用此方法的进程终止或到达指定的timeout(可选参数)。

  start():进程准备就绪,等待CPU调度

  run():strat()调用run方法,如果实例进程时未制定传入target,这star执行t默认run()方法。

  terminate():不管任务是否完成,立即停止工作进程

属性:

  authkey

  daemon:和线程的setDeamon功能一样

  exitcode(进程在运行时为None、如果为–N,表示被信号N结束)

  name:进程名字。

  pid:进程号。

三:进程间通讯:这里都是通过代码来看的

3.1首先来看一个队列,进程队列queue

from multiprocessing import Process, Queue

def f(q,n):
    q.put([42, n, ‘hello‘])

if __name__ == ‘__main__‘:
    q = Queue()
    p_list=[]
    for i in range(3):
        p = Process(target=f, args=(q,i))
        p_list.append(p)
        p.start()
    print(q.get())
    print(q.get())
    print(q.get())
    for i in p_list:
            i.join()

3.2      pipe

# import os
#
# from multiprocessing import Process, Pipe
#
# def f(conn):
#     conn.send(‘约吗‘)
#     print(conn.recv(),‘in the %s‘%os.getpid())
#     conn.close()
#
# if __name__ == ‘__main__‘:
#     parent_conn, child_conn = Pipe()
#     p = Process(target=f, args=(child_conn,))
#     p2 = Process(target=f, args=(child_conn,))
#     p.start()
#     p2.start()
#     print(parent_conn.recv())  # prints "[42, None, ‘hello‘]"
#     print(parent_conn.recv())  # prints "[42, None, ‘hello‘]"
#     parent_conn.send(‘hello‘)
#     parent_conn.send(‘hello2‘)
#
#     p.join()

4.  manager         来实现一个数据共享

from multiprocessing import Process, Manager

def f(d,l,n):
    d[n] = ‘1‘
    d[‘2‘] = 2
    d[0.25] = None
    l.append(n)
    #print(l)
    print(‘sub‘,id(d))

if __name__ == ‘__main__‘:
    with Manager() as manager:#  with open() as f==   f=open()       manager=Manager()
        d = manager.dict()

        l = manager.list(range(5))
        p_list = []

        print(‘main‘,id(d))
        for i in range(10):
            p = Process(target=f, args=(d,l,i))
            p.start()
            p_list.append(p)

        for res in p_list:
            res.join()

        print(d)
        print(l)

四:进程池

进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池序列中没有可供使用的进进程,那么程序就会等待,直到进程池中有可用进程为止。

进程池中有两个方法:

  • apply
  • apply_async
from  multiprocessing import Process, Pool
import time
import os

def Foo(i):
    time.sleep(2)
    print(‘sub %s‘%os.getpid())

    return i + 100

def Bar(arg):
    print(‘Bar:‘,os.getpid())
    print(‘-->exec done:‘, arg)

if __name__==‘__main__‘:
    pool = Pool()
    print(‘main:‘,os.getpid())
    for i in range(10):
        pool.apply_async(func=Foo, args=(i,),callback=Bar)
        #pool.apply(func=Foo, args=(i,))
    print(‘end‘)

    pool.close()
    pool.join()

第二部分:           协程

协程

协程,又称微线程,纤程。英文名Coroutine。一句话说明什么是线程:协程是一种用户态的轻量级线程。

协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。因此:

协程能保留上一次调用时的状态(即所有局部状态的一个特定组合),每次过程重入时,就相当于进入上一次调用的状态,换种说法:进入上一次离开时所处逻辑流的位置。

协程的好处:

无需线程上下文切换的开销
无需原子操作锁定及同步的开销
方便切换控制流,简化编程模型
高并发+高扩展性+低成本:一个CPU支持上万的协程都不是问题。所以很适合用于高并发处理。
缺点:

无法利用多核资源:协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上.当然我们日常所编写的绝大部分应用都没有这个必要,除非是cpu密集型应用。
进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序

我们来看例子慢慢认识协程

1.   yield支持下的协程         yield有一个并发的效果,在这里其实实现的就是一个协程

首先我们先来简单的回顾一下yield,比如说

def f():
    print("ok")
f()                 # 这种情况下回正常执行函数打印出结果为OK,看下面
def f():
    print("OK")
    yield
f()                  # 这个时候是什么都没有,为什么,这里的yield是一个生成器
print(f())        #<generator object f at 0x00000000006AC048>,那我们怎样去打印出上面的结果呢,看下面加的一些
gen = f()next(gen)
next(gen)        #这样我们就可以取到值                     注意:  gen.__next__()和next(gen)是等价的
如果我们在yield下面加上这样
print(‘ok1‘)yield     5print("OK2")        这样的话OK2也是不会打印的,因为此时yield已经折回了,当然要想打印出OK2,我们再来一个next就行,还需要一个yieldyield     7

最后面next(gen)这样就可以实现

yield  后面是可以跟参数的,那么我们如何取到yield后面的参数值呢,因为返回的其实就是next(gen),所以呢,看下面这样就可以取到返回值ret = next(gen)print(ret)               此时取到的就是返回值 
我们除了next进入生成器对象里面我们还可以通过send进入,看下面例子count = yield 5print(count)x = gen.send(10)print(x)但是如果我们开始直接就send一个值是不行的,必须传入一个空值才行,就是gen.send(None)

我这里写的有一点乱,可以看下面的代码在一步步看我的就而已理解了
def f():
    print(‘ok1‘)
    count=yield 5
    print(count)
    print(‘ok2‘)
    yield 67

#print(f())  #<generator object f at 0x00000000006AC048>

gen=f()

# ret=next(gen)
# print(ret)

next(gen)#gen.send(None)#

x=gen.send(10)
print(x)#67

再来看一个例子

import time
import queue

def consumer(name):
    print("--->starting ...")
    while True:
        new_baozi = yield
        print("[%s] is eating baozi %s" % (name, new_baozi))
        # time.sleep(1)

def producer():
    next(con)
    next(con2)
    n = 0
    while n < 5:
        n += 1
        print("\033[32;1m[producer]\033[0m is making baozi %s" % n)

        con.send(n)
        con2.send(n)

if __name__ == ‘__main__‘:
    con = consumer("c1")   #  创建一个生成器对象con
    con2 = consumer("c2")  #  创建一个生成器对象con2
    p = producer()         #  执行producer函数,p就是函数返回值

2.Greenlet  下的协程

from greenlet import greenlet
def test1():
    print(12)
    gr2.switch()
    print(34)
    gr2.switch()
def test2():
    print (56)
    gr1.switch()
    print (78)

gr1 = greenlet(test1)
gr2 = greenlet(test2)        #这里也是生成了一个对象
print(gr1)
print(gr2)结果为:

<greenlet.greenlet object at 0x000000CD25A1FCC0>
<greenlet.greenlet object at 0x000000CD25A1FDF0>
12
56
34
78

3.gevent   下 支持 的 协程

Gevent 是一个第三方库,可以轻松通过gevent实现并发同步或异步编程,在gevent中用到的主要模式是Greenlet, 它是以C扩展模块形式接入Python的轻量级协程。 Greenlet全部运行在主程序操作系统进程的内部,但它们被协作式地调度。

首先我们要装一个gevent,在file下找到setting下的这个选项就可以在里面添加各种你所需要的配置

来看一个例子

# import gevent
# import time
#
# def foo():
#     print(‘Running in foo‘,time.ctime())
#     gevent.sleep(1)                                 #这里有同学可能会问为什么不用time,如果用time的话这就是一个串行的过程,就不会切换了,
#     print(‘Explicit context switch to foo again‘,time.ctime())
#
#
# def bar():
#     print(‘Explicit context to bar‘,time.ctime())
#     gevent.sleep(2)
#     print(‘Implicit context switch back to bar‘,time.ctime())
#
# gevent.joinall([
#     gevent.spawn(foo),
#     gevent.spawn(bar),
# ])

结果为:

runing in foo Fri Oct 14 17:18:38 2016
explicit context to bar Fri Oct 14 17:18:38 2016
explicit context switch to foo again Fri Oct 14 17:18:39 2016
implicit context switch back to bar Fri Oct 14 17:18:40 2016

再来看一个爬虫的例子,比如说校花网

#爬虫
# from gevent import monkey
# monkey.patch_all()              #最大程度的利用IO阻塞
# import gevent
# from urllib.request import urlopen
# import time
# def f(url):
#     print("GET: %s" % url)
#     resp = urlopen(url)
#     data = resp.read()
#     with open("xiaohuawang.html","wb")as f:
#         f.write(data)
#     print("%d bytes received from %s." % (len(data),url))
# #l = ["http://www.python.org/","http://www.yahoo.com/","http://github.com/"]
# start = time.time()
# for url in l:
#     f(url)                   #是等价于下面的,
# gevent.joinall([
#     gevent.spawn(f,"http://www.xiaohuar.com/"),
#     # gevent.spawn(f,"http://www.yahoo.com/"),
#     # gevent.spawn(f,"http://github.com/"),
# ])
# print(time.time() - start)
#
时间: 2024-08-28 12:31:37

进程,协程的相关文章

python第五十三天--进程,协程.select.异步I/O...

进程: 1 #!usr/bin/env python 2 #-*-coding:utf-8-*- 3 # Author calmyan 4 import multiprocessing,threading,time 5 6 def run(name): 7 t=threading.Thread(target=run2)#创建新线程 8 t.start() 9 print('进程[%s],打印中...'%name) 10 time.sleep(1) 11 12 def run2(): 13 pri

11 线程进程协程

1 线程 1.1 基本应用 1.1.1 标准线程(常用) import threading def f1(arg): print(arg) t = threading.Thread(target=f1, args=(123,)) t.start() 1.1.2 自定义线程 自定义线程类既threading.Thread流程,自定义run方法 import threading class MyThread(threading.Thread): #自定义类,继承threading.Thread类 d

python学习笔记-(十四)进程&amp;协程

一. 进程 1. 多进程multiprocessing multiprocessing包是Python中的多进程管理包,是一个跨平台版本的多进程模块.与threading.Thread类似,它可以利用multiprocessing.Process对象来创建一个进程.该进程可以运行在Python程序内部编写的函数.该Process对象与Thread对象的用法类似. 创建一个Process实例,可用start()方法启动. join()方法可以等待子进程结束后再继续往下运行,通常用于进程间的同步.

Python的线程&amp;进程&amp;协程[0] -&gt; 基本概念

基本概念 / Basic Concept 0 简介与动机 / Why Multi-Thread/Multi-Process/Coroutine 在多线程(multithreaded, MT)编程出现之前,计算机程序的执行是由单个步骤序列组成的,该序列在主机的CPU中按照同步顺序执行.即无论任务多少,是否包含子任务,都要按照顺序方式进行. 然而,假定子任务之间相互独立,没有因果关系,若能使这些独立的任务同时运行,则这种并行处理方式可以显著提高整个任务的性能,这便是多线程编程. 而对于Python而

线程 进程 协程

一.什么是线程? 线程是操作系统能够进行运算调度的最小单位(程序执行流的最小单元).它被包含在进程之中,是进程中的实际运作单位.一条线程指的是一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务. 一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成.另外,线程是进程的中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源.一个线程可以创建和撤销另一

15.python并发编程(线程--进程--协程)

一.进程:1.定义:进程最小的资源单位,本质就是一个程序在一个数据集上的一次动态执行(运行)的过程2.组成:进程一般由程序,数据集,进程控制三部分组成:(1)程序:用来描述进程要完成哪些功能以及如何完成(2)数据集:是程序在执行过程中所需要使用的一切资源(3)进程控制块:用来记录进程外部特征,描述进程的执行变化过程,系统可以利用它来控制和管理进程,它是系统感知进程存在的唯一标志.3.进程的作用:是想完成多任务并发,进程之间的内存地址是相互独立的二.线程:1.定义:最小的执行单位,线程的出现是为了

第九天 线程 进程 协程 队列

详细链接http://www.cnblogs.com/alex3714/articles/5230609.html 1.线程:包含在进程中,是操作系统运算调度的最小单位,是一串指令的集合,直接与cpu交互 2进程:进程是一个程序各种资源的集合.操作系统通过管理这个集合进而运行程序,进程本身并不执行,进程通过调用线程来调度cpu. 3.不同点: 一个线程可以控制和操作同一进程里的其他线程,但是进程只能操作子进程 创建新线程很简单,但是创建一个子进程需要对父进程进行拷贝 线程共享内存,进程的内存是独

Python的线程&amp;进程&amp;协程[0] -&gt; 线程 -&gt; 多线程的建立与使用

常用的多线程功能实现 目录 生成线程的三种方法 单线程与多线程对比 守护线程的设置 1 生成线程的三种方法 三种方式分别为: 创建一个Thread实例,传给它一个函数 创建一个Thread实例,传给它一个可调用的类实例 派生Thread的子类,并创建子类的实例 # There are three ways to create a thread # The first is create a thread instance, and pass a function # The second one

Python的线程&amp;进程&amp;协程[2] -&gt; 进程 -&gt; 多进程的基本使用

多进程的基本使用 1 subprocess 常用函数示例 首先定义一个子进程调用的程序,用于打印一个输出语句,并获取命令行参数 1 import sys 2 print('Called_Function.py called, Hello world.') 3 try: 4 print('Got para', sys.argv[1:]) 5 except: 6 pass 再定义主函数,即父进程,分别测试 run() / call() / check_call() / getstatusoutput

Python的线程&amp;进程&amp;协程[0] -&gt; 线程 -&gt; 多线程锁的使用

锁与信号量 目录 添加线程锁 锁的本质 互斥锁与可重入锁 死锁的产生 锁的上下文管理 信号量与有界信号量 1 添加线程锁 由于多线程对资源的抢占顺序不同,可能会产生冲突,通过添加线程锁来对共有资源进行控制. 1 import atexit 2 from random import randrange 3 from threading import Thread, Lock, current_thread # or currentThread 4 from time import ctime, s