python 多线程和多进程的区别 mutiprocessing theading

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python 多线程和多进程的区别 mutiprocessing theading相关的知识,希望对你有一定的参考价值。

在socketserver服务端代码中有这么一句:

server = socketserver.ThreadingTCPServer((ip,port), MyServer)

ThreadingTCPServer这个类是一个支持多线程和TCP协议的socketserver,它的继承关系是这样的:

class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass

右边的TCPServer实际上是主要的功能父类,而左边的ThreadingMixIn则是实现了多线程的类, ThreadingTCPServer自己本身则没有任何代码。

MixIn在Python的类命名中很常见,称作“混入”,戏称“乱入”,通常为了某种重要功能被子类继承。

我们看看一下ThreadingMixIn的源代码:

class ThreadingMixIn:

daemon_threads = False

def process_request_thread(self, request, client_address):
try:
self.finish_request(request, client_address)
self.shutdown_request(request)
except:
self.handle_error(request, client_address)
self.shutdown_request(request)

def process_request(self, request, client_address):

t = threading.Thread(target = self.process_request_thread,
args = (request, client_address))
t.daemon = self.daemon_threads
t.start()

在ThreadingMixIn类中,其实就定义了一个属性,两个方法。其中的process_request()方法实际调用的正是Python内置的多线程模块threading。这个模块是Python中所有多线程的基础,socketserver本质上也是利用了这个模块。

socketserver通过threading模块,实现了多线程任务处理能力,可以同时为多个客户提供服务。

那么,什么是线程,什么是进程?

进程是程序(软件,应用)的一个执行实例,每个运行中的程序,可以同时创建多个进程,但至少要有一个。每个进程都提供执行程序所需的所有资源,都有一个虚拟的地址空间、可执行的代码、操作系统的接口、安全的上下文(记录启动该进程的用户和权限等等)、唯一的进程ID、环境变量、优先级类、最小和最大的工作空间(内存空间)。进程可以包含线程,并且每个进程必须有至少一个线程。每个进程启动时都会最先产生一个线程,即主线程,然后主线程会再创建其他的子线程。

线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不独立拥有系统资源,但它可与同属一个进程的其它线程共享该进程所拥有的全部资源。每一个应用程序都至少有一个进程和一个线程。在单个程序中同时运行多个线程完成不同的被划分成一块一块的工作,称为多线程。

举个例子,某公司要生产一种产品,于是在生产基地建设了很多厂房,每个厂房内又有多条流水生产线。所有厂房配合将整个产品生产出来,单个厂房内的流水线负责生产所属厂房的产品部件,每个厂房都拥有自己的材料库,厂房内的生产线共享这些材料。公司要实现生产必须拥有至少一个厂房一条生产线。换成计算机的概念,那么这家公司就是应用程序,厂房就是应用程序的进程,生产线就是某个进程的一个线程。

线程的特点:

线程是一个execution context(执行上下文),即一个cpu执行时所需要的一串指令。假设你正在读一本书,没有读完,你想休息一下,但是你想在回来时继续先前的进度。有一个方法就是记下页数、行数与字数这三个数值,这些数值就是execution context。如果你的室友在你休息的时候,使用相同的方法读这本书。你和她只需要这三个数字记下来就可以在交替的时间共同阅读这本书了。

线程的工作方式与此类似。CPU会给你一个在同一时间能够做多个运算的幻觉,实际上它在每个运算上只花了极少的时间,本质上CPU同一时刻只能干一件事,所谓的多线程和并发处理只是假象。CPU能这样做是因为它有每个任务的execution context,就像你能够和你朋友共享同一本书一样。

进程与线程区别:

    同一个进程中的线程共享同一内存空间,但进程之间的内存空间是独立的。

    同一个进程中的所有线程的数据是共享的,但进程之间的数据是独立的。

    对主线程的修改可能会影响其他线程的行为,但是父进程的修改(除了删除以外)不会影响其他子进程。

    线程是一个上下文的执行指令,而进程则是与运算相关的一簇资源。

    同一个进程的线程之间可以直接通信,但是进程之间的交流需要借助中间代理来实现。

    创建新的线程很容易,但是创建新的进程需要对父进程做一次复制。

    一个线程可以操作同一进程的其他线程,但是进程只能操作其子进程。

    线程启动速度快,进程启动速度慢(但是两者运行速度没有可比性)。

    由于现代cpu已经进入多核时代,并且主频也相对以往大幅提升,多线程和多进程编程已经成为主流。Python全面支持多线程和多进程编程,同时还支持协程。

参考技术A GIL在Python中,由于历史原因(GIL),使得Python中多线程的效果非常不理想.GIL使得任何时刻Python只能利用一个CPU核,并且它的调度算法简单粗暴:多线程中,让每个线程运行一段时间t,然后强行挂起该线程,继而去运行其他线程,如此周而复始,直到所有线程结束.这使得无法有效利用计算机系统中的"局部性",频繁的线程切换也对缓存不是很友好,造成资源的浪费.据说Python官方曾经实现了一个去除GIL的Python解释器,但是其效果还不如有GIL的解释器,遂放弃.后来Python官方推出了"利用多进程替代多线程"的方案,在Python3中也有concurrent.futures这样的包,让我们的程序编写可以做到"简单和性能兼得".多进程/多线程+Queue一般来说,在Python中编写并发程序的经验是:计算密集型任务使用多进程,IO密集型任务使用多进程或者多线程.另外,因为涉及到资源共享,所以需要同步锁等一系列麻烦的步骤,代码编写不直观.另外一种好的思路是利用多进程/多线程+Queue的方法,可以避免加锁这样麻烦低效的方式.现在在Python2中利用Queue+多进程的方法来处理一个IO密集型任务.假设现在需要下载多个网页内容并进行解析,单进程的方式效率很低,所以使用多进程/多线程势在必行.我们可以先初始化一个tasks队列,里面将要存储的是一系列dest_url,同时开启4个进程向tasks中取任务然后执行,处理结果存储在一个results队列中,最后对results中的结果进行解析.最后关闭两个队列.下面是一些主要的逻辑代码.#-*-coding:utf-8-*-#IO密集型任务#多个进程同时下载多个网页#利用Queue+多进程#由于是IO密集型,所以同样可以利用threading模块importmultiprocessingdefmain():tasks=multiprocessing.JoinableQueue()results=multiprocessing.Queue()cpu_count=multiprocessing.cpu_count()#进程数目==CPU核数目create_process(tasks,results,cpu_count)#主进程马上创建一系列进程,但是由于阻塞队列tasks开始为空,副进程全部被阻塞add_tasks(tasks)#开始往tasks中添加任务parse(tasks,results)#最后主进程等待其他线程处理完成结果defcreate_process(tasks,results,cpu_count):for_inrange(cpu_count):p=multiprocessing.Process(target=_worker,args=(tasks,results))#根据_worker创建对应的进程p.daemon=True#让所有进程可以随主进程结束而结束p.start()#启动def_worker(tasks,results):whileTrue:#因为前面所有线程都设置了daemon=True,故不会无限循环try:task=tasks.get()#如果tasks中没有任务,则阻塞result=_download(task)results.put(result)#someexceptionsdonothandledfinally:tasks.task_done()defadd_tasks(tasks):forurlinget_urls():#get_urls()returnaurls_listtasks.put(url)defparse(tasks,results):try:tasks.join()exceptKeyboardInterruptaserr:print"Taskshasbeenstopped!"printerrwhilenotresults.empty():_parse(results)if__name__=='__main__':main()利用Python3中的concurrent.futures包在Python3中可以利用concurrent.futures包,编写更加简单易用的多线程/多进程代码.其使用感觉和Java的concurrent框架很相似(借鉴?)比如下面的简单代码示例defhandler():futures=set()withconcurrent.futures.ProcessPoolExecutor(max_workers=cpu_count)asexecutor:fortaskinget_task(tasks):future=executor.submit(task)futures.add(future)defwait_for(futures):try:forfutureinconcurrent.futures.as_completed(futures):err=futures.exception()ifnoterr:result=future.result()else:raiseerrexceptKeyboardInterruptase:forfutureinfutures:future.cancel()print"Taskhasbeencanceled!"printereturnresult总结要是一些大型Python项目也这般编写,那么效率也太低了.在Python中有许多已有的框架使用,使用它们起来更加高效.本回答被提问者采纳

多线程和多进程的区别

类似前言一样的东西

多线程和多进程各有优缺点,没有哪个是最好,只有在不同情况下,哪种是更好的

参考文章

https://blog.csdn.net/lishenglong666/article/details/8557215 ---优秀的分割线---

首先先从大概念来解释多线程和多进程的区别,多线程就是CPU资源的分配,多进程就是电脑内存的分配


举个例子,进程相当于公路,线程相当于是分岔路 电脑需要一条公路来运输数据,但是不同的数据有不同的目的地

但是开新的公路代价太高,所以可以在一条公路上分成两条、三条道

不需要的时候小道就销毁掉,需要就再开

多线程相比于多进程来说,线程创建、销毁的代价低,其次进程多了,内存占用的也多,但是CPU利用率低

但是也不是说多进程就一无是处,多进程的可靠性比多线程高,因为进程和进程之间不会互相影响,而多线程有可能会因为一个线程的爆炸而导致进程崩溃

在网上看到的一篇关于这个的表,觉得不错,故而转载

举个用多线程的例子根据上面的优缺点来判断,需要频繁创建、销毁的优先用线程拿之前培训的一个脚本来说

 
   
   
 
  1. #coding=utf-8

  2. import socket

  3. import threading

  4. import time

  5. #创建socket

  6. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  


  7. #监听端口

  8. s.bind(("127.0.0.1",8888))

  9. print("Success")

  10. #指定等待最大连接数量

  11. s.listen(5)


  12. def tcp(sock,addr):

  13.    print ("connection from %s:%s " % addr)

  14.    sock.send(b"welcome, what's your name") #发送数据给客户端

  15.    while True:

  16.        data = sock.recv(100)

  17.        time.sleep(1)

  18.        if data=="exit":

  19.            sock.send(b"quit")

  20.            break

  21.        sock.send(b"hello "+data)

  22.    sock.close()


  23. while True:

  24.    sock,addr = s.accept() #接受所有来自客户端的内容

  25.    t = threading.Thread(target=tcp,args=(sock,addr)) #创建线程

  26.    t.start() #开启线程

26-29是多线程的部分,这里的作用呢,就是来一个用户,就开启一个线程,去处理这个用户的请求,当用户断开连接时,就销毁线程


还有一个场景,就是需要进行大量计算,或者处理大量数据的,也可以用到多线程比如说用扫描网站的工具扫描网站后台,只有一个线程去处理这一个网站时,他需要单独的去完成3000+个的枚举,但是假如有60个线程的话,那么每个线程就只需要500+个的枚举,加快速度的同时将空闲的CPU资源利用起来了

那么具体什么时候用到多进程呢,因为本人基本上用的都是单进程多线程的,所以解释的会不到位,有意见的大佬可以指出来,马上改

进程和线程的差别,我觉得就是工作量上的问题,任务量比较小的时候,线程是占优的,任务量大的时候,进程就占优了,进程的例子举不出来,阔以看下表

所以在日常工作时,处理工作量大的时候,进程就是不错的选择了,而像我平时处理小数据的,脚本用线程来处理就是绝佳的了

结尾

讲道理,上面的参考链接举的例子很清楚了,而且讲的也明白,而且我的用法都是单进多线,没啥必要写这篇文章,写了也不全面,但是既然学弟都这么说了,想让我写上一篇,那我只好说说自己的愚见,各大佬不喜勿喷


以上是关于python 多线程和多进程的区别 mutiprocessing theading的主要内容,如果未能解决你的问题,请参考以下文章

多线程和多进程模式有啥区别

python(33)多进程和多线程的区别

python多进程和多线程的区别

python 多线程和多进程的区别 mutiprocessing theading

python 多进程和多线程配合

python 多线程和多进程的区别 mutiprocessing theading