zoukankan      html  css  js  c++  java
  • Python 进程、协程

    __author__ = 'alex'
    #coding:utf-8
    from multiprocessing import Process
    
    def foo(i):
        print (i)
    
    if __name__ == '__main__':
        for i in range(10):
            p = Process(target=foo,args=(i,))
            p.start()

    进程的数据默认不共享

    #coding:utf-8
    from multiprocessing import Process
    
    def foo(i,li):
        li.append(i)
        print ('li is ',li)
        # print (i)
    
    li = []
    if __name__ == '__main__':
    
        for i in range(10):
            p = Process(target=foo,args=(i,li))
            p.start()

    输出结果:

    li is  [1]
    li is  [0]
    li is  [3]
    li is  [2]
    li is  [5]
    li is  [7]
    li is  [4]
    li is  [6]
    li is  [8]
    li is  [9]

    这个跟我们设想要的结果不一致,我们需要的是for循环中的数据一个个的被append到列表中去,这就涉及到了进程间的通信。

    #coding:utf-8
    from multiprocessing import Process
    from multiprocessing import queues
    import multiprocessing
    import time
    
    def foo(i,q):
        time.sleep(1)
        q.put(i)
        # time.sleep(1)
        print ('qsize is ',q.qsize())
        # print (i)
    
    q = queues.Queue(ctx=multiprocessing)
    if __name__ == '__main__':
    
        for i in range(10):
            p = Process(target=foo,args=(i,q))
            p.start()

    1,使用multiprocessing模块中的queues类,可以实现进程间的通信,输出结果:

    qsize is  1
    qsize is  2
    qsize is  3
    qsize is  4
    qsize is  5
    qsize is  6
    qsize is  7
    qsize is  8
    qsize is  10
    qsize is  10

    2,也可以利用python的Array来实现,Array较之list的不同在于,数组的元素位置都是在一起的,大小是事先分配好的。

    #coding:utf-8
    from multiprocessing import Process
    from multiprocessing import queues
    import multiprocessing
    import time
    from multiprocessing import Array
    
    def foo(i,arr):
        time.sleep(2)
        arr[i] = i
        # time.sleep(1)
        # print ('qsize is ',q.qsize())
        # print (i)
        for item in arr:
            print (item)
        print ("===================")
    
    arr = Array('i',10)
    
    if __name__ == '__main__':
    
        for i in range(10):
            p = Process(target=foo,args=(i,arr))
            p.start()

    执行最终结果是:

    0
    1
    2
    3
    4
    5
    6
    7
    8
    9

    但是因为线程之间无法确定哪个线程先执行完的(CPU的调度是随机的),所以刚开始的数据可能是无序的。

    3,也可以使用一个特殊的dict()类来实现,但是下面的代码执行有问题,因为是用fork()的机制来产生进程的,所以在windows下面不支持,但是在Linux和MAC中是可以支持的,未测试!

    进程间的通信使用的也是socket的方式来实现的,在下面的代码中,main函数里面sleep(2)了2秒,原因是主进程和子进程在通信过程中,如果子进程还没有执行完,但是子进程已经执行完退出了,那么子进程将不能进行消息的收发了,因而不能实现进程间通信了,如果把sleep的时间改到0.1秒,那么可以看到的结果是,有一部分的数据执行出来了,剩余的程序未执行完就报错了。

    
    
    #coding:utf-8
    from multiprocessing import Process
    from multiprocessing import queues
    import multiprocessing
    import time
    from multiprocessing import Array
    from multiprocessing import Manager

    manage = Manager()
    dic = manage.dict()

    def foo(i,dic):

    dic[i] = i +100
    print (dic.values())


    if __name__ == '__main__':
    for i in range(10):
    p = Process(target=foo,args=(i,dic))
    p.start()
    time.sleep(2)

     进程跟线程一样,操作同一份数据的时候也需要加锁:

    from multiprocessing import Process,Array
    import time
    
    arr = Array('i',1)
    arr[0] = 10
    
    def foo(arr):
        arr[0] -= 1
        time.sleep(1)
        print (arr[0])
    
    if __name__ == '__main__':
        for i in range(10):
            p = Process(target=foo,args=(arr,))
            p.start()

    因为添加了sleep(1),所以每次执行循环的时候,每个子进程都执行了一遍减一的操作,最终所有的输出结果都是0

    0
    0
    0
    0
    0
    0
    0
    0
    0
    0

    因此,我们需要给进程加锁:

    from multiprocessing import Process,Array
    import time
    from multiprocessing import RLock
    
    lk = RLock()
    arr = Array('i',1)
    arr[0] = 10
    
    def foo(arr,lc):
        lc.acquire()
        arr[0] -= 1
        time.sleep(1)
        print (arr[0])
        lc.release()
    
    if __name__ == '__main__':
        for i in range(10):
            p = Process(target=foo,args=(arr,lk))
            p.start()

    执行结果:

    9
    8
    7
    6
    5
    4
    3
    2
    1
    0

     进程锁:

    from multiprocessing import Pool
    from multiprocessing import Process
    import time
    
    def foo(arg):
        time.sleep(1)
        print (arg)
    
    if __name__ == '__main__':
        p = Pool(5)
        for i in range(10):
            p.apply(func=foo,args=(i,))

    执行结果,每隔一秒打印一个数值:

    0
    1
    2
    3
    4
    5
    6
    7
    8
    9

    改成另外的写法:

    from multiprocessing import Pool
    from multiprocessing import Process
    import time
    
    def foo(arg):
        time.sleep(1)
        print (arg)
    
    if __name__ == '__main__':
        p = Pool(5)
        for i in range(10):
            p.apply_async(func=foo,args=(i,))
        p.close()
        p.join()

    在执行join方法之前必须先执行close()或者terminate()方法。

    执行结果:

    0
    1
    2
    3
    4
    5
    6
    7
    8
    9

    如果用terminate方法改写:

    from multiprocessing import Pool
    from multiprocessing import Process
    import time
    
    def foo(arg):
        time.sleep(1)
        print (arg)
    
    if __name__ == '__main__':
        p = Pool(5)
        for i in range(10):
            p.apply_async(func=foo,args=(i,))
        time.sleep(2)
        p.terminate()
        # p.close()
        p.join()

    执行结果:

    0
    1
    2
    3
    4

    terminate表示当前的子进程执行完毕就不执行了,close表示所有的进程都执行完毕之后才执行主进程。

    协程是把一个线程分解了,成为多个“微线程”,实现IO操作,要实现协程,到导入greenlet模块。首先我们要安装这个模块。

    我们看到,在python安装的时候,已经安装了pip模块和setuptools模块,现在我们需要利用pip3模块来安装。

    pip3,easy_install命令都在C:UsersalexAppDataLocalProgramsPythonPython35Scripts这个目录下面,运行CMD到这个模块,然后执行

    C:UsersalexAppDataLocalProgramsPythonPython35Scripts>pip3 install greenlet
    Collecting greenlet
      Downloading greenlet-0.4.10-cp35-cp35m-win_amd64.whl
    Installing collected packages: greenlet
    Successfully installed greenlet-0.4.10
    You are using pip version 8.1.1, however version 8.1.2 is available.
    You should consider upgrading via the 'python -m pip install --upgrade pip' comm
    and.

    可以看到开始的截图,我们已经安装成功了。通过help('modules')模块可以查看已经安装的模块。

     greenlet模块

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

    执行结果:

    12
    56
    34
    78

    gevent模块

    import gevent
    def foo():
        print ("foo begin")
        gevent.sleep(0)
        print ("foo end")
    
    
    def bar():
        print ("bar begin")
        gevent.sleep(0)
        print ("bar end")
    
    gevent.joinall([gevent.spawn(foo),gevent.spawn(bar)])

    执行结果:

    foo begin
    bar begin
    foo end
    bar end

    gevent的使用:

    
    
    import gevent
    from gevent import monkey;monkey.patch_all() #修改了原有的socket方法,当你发起请求的时候,默认socket不会告知程序执行完成与否,pathch_all方法会返回                            #执行完成的通知
    import requests import time def send(url): print("GET %s" %url) resp = requests.get(url) data = resp.text print ('%s has received by %s'%(len(data),url)) gevent.joinall([gevent.spawn(send,'https://www.python.org'), gevent.spawn(send,'http://www.baidu.com') ])
    执行结果:

    GET https://www.python.org
    GET http://www.baidu.com
    2381 has received by http://www.baidu.com
    47412 has received by https://www.python.org

  • 相关阅读:
    离线修改注册表
    在Spring3中,配置DataSource的方法有6种。
    windows设置java环境变量
    三种配置linux环境变量的方法(以java为例)
    java call sap
    Tomcat 解决The code of method _jspService(HttpServletRequest, HttpServletResponse) is exceeding the 65535 bytes limit
    window上安装pymysql
    Python中的str与bytes之间的转换的三种方法
    安装sqlite3.8的方法
    os.walk的用法
  • 原文地址:https://www.cnblogs.com/python-study/p/5832006.html
Copyright © 2011-2022 走看看