签到成功

知道了

CNDBA社区CNDBA社区

Python 多线程与多进程 概念和操作示例

2017-08-20 15:04 2692 0 转载 Python
作者: dave

1 概念理解
对于操作系统来说,一个任务就是一个进程。例如打开浏览器,打开word,打开记事本等等,都是独立的任务,它们各自为一个或者多个进程。这里要注意的是,同一种任务打开多个,分别属于不同进程,例如chrome打开多个标签,实际上它创建了多个进程。
对于一个任务来说,它有很多子任务,例如播放器,既要解码视频、也要解码音频,所以在进程下存在多线程。在一个进程下一定存在一个线程,可以称它为主线程。
操作系统创建进程时,会单独为每一个进程分配各自的资源,进程与进程之间相互隔离。而进程内的线程,则共享了当前进程内的资源。可见,操作系统执行的粒度是线程,分配资源的粒度是进程,我们的多任务操作系统,在单核CPU上是在各个线程上不断切换而达到目的,而在多核CPU上则能同时执行多个线程任务。
Python能很方便地支持多进程、多线程编程,接下来就简单记录下,最后再记录下两者优缺点。

2 多进程
在Linux系统下,有一个非常特殊的函数,fork()。它调用一次,返回两次,操作系统自动把当前进程(父进程)复制了一份(子进程),然后分别在父进程和子进程内返回。子进程永远返回0,父进程返回子进程的ID。经过这样做,父进程就能fork出很多子进程,并可以记录下子进程的ID号了,子进程可以通过getppid()来获取父进程ID。fork()仅在Unix/Linux下使用,windows则不行。
所以,在Python中,存在一个跨平台的包mutiprocessing,通过引入包中的Process类,就可以创建多进程程序了,可以创建一个进程p=Process(target=func,args=(*,)),然后利用p.start()及p.join()来执行了。以上的join()方法可以等待子进程结束后才往下执行,通常用于进程间同步。
另外,可以用进程池的方式,例如p=Pool(n),然后p.apply_async(func,args),这里可以使用n种不同的参数传入,建立不同的进程。用这种方式时,在调用join()方法前,要先调用close()方法,使得不能再添加新进程。
mutiprocessing包里提供了Queue、Pipe等多种进程间通信的方法。可以直接引入Queue类,然后实例化一个对象。则不同的进程可以使用put方法发信息,同时可以使用get方法取信息。

3 多线程
多个任务可以创建多个进程来完成,同时也可以创建多个线程来完成,线程是操作系统直接的执行单元。
Python含有threading这个高级模块,要启动一个线程,就是把一个函数传出并创建Thread实例,然后调用start()方法开始执行,例如t=threading.Thread(target=func,name=*),注意这里的name属性,它是给线程命名的,缺省值为Thread-1···。要注意的是,刚才说了,任何一个进程都含有一个线程,而这个主线程则执行着我们编写的程序,可以调用threading.current_thread().name来查看它,它的名字就叫MainThread。
在多线程编程中,有一个最大的问题就在于进程内的资源被各个线程所共享,进程内任何变量都可以被任何一个线程修改,因此,线程之间若去修改同一个变量,则可能导致程序Bug。所以,引入了锁机制。
当某个线程去修改某个变量时,可以在变量所在的方法内加一把锁,使得其他线程不能同时执行该方法,只有释放了锁后,其他线程才能去获得锁并获得修改权。创建一个锁是通过lock=threading.Lock()来实现的,可以使用try···finally···语句,在try之前使用lock.acquire()获得锁,然后在try语句里面修改变量,然后在finally语句里加lock.release()来保证锁一定被释放,避免成为一个死锁。

4 区别于联系
多进程的优点是稳定性好,一个子进程崩溃了,不会影响主进程以及其余进程。但是缺点是创建进程的代价非常大,因为操作系统要给每个进程分配固定的资源,并且,操作系统对进程的总数会有一定的限制,若进程过多,操作系统调度都会存在问题,会造成假死状态。多线程优点是效率较高一些,但是致命的缺点是任何一个线程崩溃都可能造成整个进程的崩溃,因为它们共享了进程的内存资源池。
对于任务数来说,无论是多进程或者多线程,都不能太多。因为操作系统在切换任务时,会有一系列的保护现场措施,这要花费相当的系统资源,若任务过多,则大部分资源都被用做干这些了,结果就是所有任务都做不好,所以操作系统会限制进程的数量。
另外,考虑计算密集型及IO密集型应用程序。对于计算密集型,多任务势必造成资源浪费。对于IO密集型,因为IO速度远低于CPU计算速度,所以使用多任务方式可以大大增大程序运行效率。

5 操作示例

import os
import threading
import multiprocessing
import time

count_thread = 0
count_process = 0

# worker function
def worker1(sign, lock):
    global count_thread
    lock.acquire()
    count_thread += 1
    print(sign, os.getpid(),time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
    lock.release()

def worker2(sign, lock):
    global count_process
    lock.acquire()
    count_process += 1
    print(sign, os.getpid(),time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
    lock.release()



if __name__ == '__main__':
    # Main
    print('Main:', os.getpid())

    # Multi-thread
    joblist = []
    lock  = threading.Lock()
    for i in range(5):
        thread = threading.Thread(target=worker1,args=('thread',lock))
        thread.start()
        joblist.append(thread)

    for thread in joblist:
        thread.join()

    # Multi-process
    joblist = []
    lock = multiprocessing.Lock()
    for i in range(5):
        process = multiprocessing.Process(target=worker2,args=('process',lock))
        process.start()
        joblist.append(process)

    for process in joblist:
        process.join()

    print count_thread
    print count_process

输出结果:
('Main:', 14668)
('thread', 14668, '2017-08-20 14:59:48')
('thread', 14668, '2017-08-20 14:59:48')
('thread', 14668, '2017-08-20 14:59:48')
('thread', 14668, '2017-08-20 14:59:48')
('thread', 14668, '2017-08-20 14:59:48')
('process', 16780, '2017-08-20 14:59:48')
('process', 10992, '2017-08-20 14:59:48')
('process', 12656, '2017-08-20 14:59:48')
('process', 4360, '2017-08-20 14:59:48')
('process', 17140, '2017-08-20 14:59:48')
5
0


http://www.cndba.cn/dave/article/2155 http://www.cndba.cn/dave/article/2155
http://www.cndba.cn/dave/article/2155
http://www.cndba.cn/dave/article/2155 http://www.cndba.cn/dave/article/2155
http://www.cndba.cn/dave/article/2155
http://www.cndba.cn/dave/article/2155 http://www.cndba.cn/dave/article/2155
http://www.cndba.cn/dave/article/2155
http://www.cndba.cn/dave/article/2155
用户评论
* 以下用户言论只代表其个人观点,不代表CNDBA社区的观点或立场
dave

dave

关注

人的一生应该是这样度过的:当他回首往事的时候,他不会因为虚度年华而悔恨,也不会因为碌碌无为而羞耻;这样,在临死的时候,他就能够说:“我的整个生命和全部精力,都已经献给世界上最壮丽的事业....."

  • 2261
    原创
  • 3
    翻译
  • 578
    转载
  • 191
    评论
  • 访问:8030500次
  • 积分:4346
  • 等级:核心会员
  • 排名:第1名
精华文章
    最新问题
    查看更多+
    热门文章
      热门用户
      推荐用户
        Copyright © 2016 All Rights Reserved. Powered by CNDBA · 皖ICP备2022006297号-1·

        QQ交流群

        注册联系QQ