进程和线程python实现和对比

本文介绍了Python中进程和线程的创建与管理,包括Process对象的使用、进程间通信的Queue以及进程池Pool。通过示例展示了如何在进程中传递参数,并讨论了进程间的通信方式。同时,提到了多进程、多线程和协程的概念及其应用场景,以及多线程竞争和锁的使用,指出锁可能导致的死锁问题。
摘要由CSDN通过智能技术生成

进程总结
进程:程序运行在操作系统上的一个实例,就称之为进程。进程需要相应的系统资源:内存、时间
片、pid。
创建进程:
1.首先要导入 multiprocessing 中的 Process;
2.创建一个 Process 对象;
3.创建 Process 对象时,可以传递参数;

p = Process(target=XXX, args=(元组,) , kwargs={key:value})
target = XXX 指定的任务函数,不用加()
args=(元组,) , kwargs={key:value} 给任务函数传递的参数

4.使用 start()启动进程;
5.结束进程。
Process 语法结构:
Process([group [, target [, name [, args [, kwargs]]]]])
target:如果传递了函数的引用,可以让这个子进程就执行函数中的代码
args:给 target 指定的函数传递的参数,以元组的形式进行传递
kwargs:给 target 指定的函数传递参数,以字典的形式进行传递
name:给进程设定一个名字,可以省略
group:指定进程组,大多数情况下用不到
Process 创建的实例对象的常用方法有:
start():启动子进程实例(创建子进程)
is_alive():判断进程子进程是否还在活着
join(timeout):是否等待子进程执行结束,或者等待多少秒
terminate():不管任务是否完成,立即终止子进程
Process 创建的实例对象的常用属性:
name:当前进程的别名,默认为 Process-N,N 为从 1 开始递增的整数
pid:当前进程的 pid(进程号)
给子进程指定函数传递参数 Demo:
1.import osfrom multiprocessing import Process
2.import time
3.
4.def pro_func(name, age, **kwargs):
5. for i in range(5):
6. print(“子进程正在运行中,name=%s, age=%d, pid=%d” %(name, age, os.getpid()))
7. print(kwargs)
8. time.sleep(0.2)
9.
10.if name == ‘main’:
11. # 创建 Process 对象
12. p = Process(target=pro_func, args=(‘小明’,18), kwargs={‘m’: 20})
13. # 启动进程
14. p.start()
15. time.sleep(1)
16. # 1 秒钟之后,立刻结束子进程
17. p.terminate()
18. p.join()
注意:进程间不共享全局变量。
进程之间的通信-Queue
在初始化 Queue()对象时,(例如 q=Queue(),若在括号中没有指定最大可接受的消息数量,或数
量为负值时,那么就代表可接受的消息数量没有上限-直到内存的尽头)
Queue.qsize():返回当前队列包含的消息数量。
Queue.empty():如果队列为空,返回 True,反之 False。
Queue.full():如果队列满了,返回 True,反之 False。
Queue.get([block[,timeout]]):获取队列中的一条消息,然后将其从队列中移除,block 默认值为
True。
如果 block 使用默认值,且没有设置 timeout(单位秒),消息列队如果为空,此时程序将被阻塞
(停在读取状态),直到从消息列队读到消息为止,如果设置了 timeout,则会等待 timeout 秒,若还
没读取到任何消息,则抛出"Queue.Empty"异常;
如果 block 值为 False,消息列队如果为空,则会立刻抛出"Queue.Empty"异常;
Queue.get_nowait():相当 Queue.get(False);
Queue.put(item,[block[, timeout]]):将 item 消息写入队列,block 默认值为 True;
如果 block 使用默认值,且没有设置 timeout(单位秒),消息列队如果已经没有空间可写入,此
时程序将被阻塞(停在写入状态),直到从消息列队腾出空间为止,如果设置了 timeout,则会等待
timeout 秒,若还没空间,则抛出"Queue.Full"异常;
如果 block 值为 False,消息列队如果没有空间可写入,则会立刻抛出"Queue.Full"异常;
Queue.put_nowait(item):相当 Queue.put(item, False);
进程间通信 Demo:

1.from multiprocessing import Process, Queueimport os, time, random
2.# 写数据进程执行的代码:def write(q):
3. for value in ['A', 'B', 'C']:
4. print('Put %s to queue...' % value)
5. q.put(value)
6. time.sleep(random.random())
7.# 读数据进程执行的代码:def read(q):
8. while True:
9. if not q.empty():
10. value = q.get(True)
11. print('Get %s from queue.' % value)
12. time.sleep(random.random())
13. else:
14. break
15.if __name__=='__main__':
16. # 父进程创建 Queue,并传给各个子进程:
17. q = Queue()
18. pw = Process(target=write, args=(q,))
19. pr = Process(target=read, args=(q,))
20. # 启动子进程 pw,写入:
21. pw.start()
22. # 等待 pw 结束:
23. pw.join()
24. # 启动子进程 pr,读取:
25. pr.start()
26. pr.join()
27. # pr 进程里是死循环,无法等待其结束,只能强行终止:
28. print('')
29. print('所有数据都写入并且读完')

进程池 Pool

1.# -*- coding:utf-8 -*-
2.from multiprocessing import Poolimport os, time, random
3.def worker(msg):
4. t_start = time.time()
5. print("%s 开始执行,进程号为%d" % (msg,os.getpid()))
6. # random.random()随机生成 0~1 之间的浮点数
7. time.sleep(random.random()*2)
8. t_stop = time.time()
9. print(msg,"执行完毕,耗时%0.2f" % (t_stop-t_start))
10.
11.po = Pool(3) # 定义一个进程池,最大进程数 3
12.for i in range(0,10):
13. # Pool().apply_async(要调用的目标,(传递给目标的参数元祖,))
14. # 每次循环将会用空闲出来的子进程去调用目标
15. po.apply_async(worker,(i,))
16.
17.print("----start----")
18.po.close() # 关闭进程池,关闭后 po 不再接收新的请求
19.po.join() # 等待 po 中所有子进程执行完成,必须放在 close 语句之后
20.print("-----end-----")

multiprocessing.Pool 常用函数解析:
 apply_async(func[, args[, kwds]]) :使用非阻塞方式调用 func(并行执行,堵塞方式必须等待
上一个进程退出才能执行下一个进程),args 为传递给 func 的参数列表,kwds 为传递给 func
的关键字参数列表;
close():关闭 Pool,使其不再接受新的任务;
terminate():不管任务是否完成,立即终止;
join():主进程阻塞,等待子进程的退出, 必须在 close 或 terminate 之后使用;
进程池中使用 Queue
如果要使用 Pool 创建进程,就需要使用 multiprocessing.Manager()中的 Queue(),而不是
multiprocessing.Queue(),否则会得到一条如下的错误信息:
RuntimeError: Queue objects should only be shared between processes through
inheritance.

1.from multiprocessing import Manager,Poolimport os,time,random
2.def reader(q):
3. print("reader 启动(%s),父进程为(%s)" % (os.getpid(), os.getppid()))
4. for i in range(q.qsize()):
5. print("reader 从 Queue 获取到消息:%s" % q.get(True))
6.def writer(q):
7. print("writer 启动(%s),父进程为(%s)" % (os.getpid(), os.getppid()))
8. for i in "itcast":
9. q.put(i)
10.if __name__=="__main__":
11. print("(%s) start" % os.getpid())
12. q = Manager().Queue() # 使用 Manager 中的 Queue
13. po = Pool()
14. po.apply_async(writer, (q,))
15.
16. time.sleep(1) # 先让上面的任务向 Queue 存入数据,然后再让下面的任务开始从中取数据
17.
18. po.apply_async(reader, (q,))
19. po.close()
20. po.join()
21. print("(%s) End" % os.getpid())
  1. 谈谈你对多进程,多线程,以及协程的理解,项目是否用?(2018-3-30-lxy)
    这个问题被问的概率相当之大,其实多线程,多进程,在实际开发中用到的很少,除非是那些对项
    目性能要求特别高的,有的开发工作几年了,也确实没用过,你可以这么回答,给他扯扯什么是进程,
    线程(cpython 中是伪多线程)的概念就行,实在不行你就说你之前写过下载文件时,用过多线程技术,
    或者业余时间用过多线程写爬虫,提升效率。
    进程:一个运行的程序(代码)就是一个进程,没有运行的代码叫程序,进程是系统资源分配的最
    小单位,进程拥有自己独立的内存空间,所以进程间数据不共享,开销大。
    线程: 调度执行的最小单位,也叫执行路径,不能独立存在,依赖进程存在一个进程至少有一个
    线程,叫主线程,而多个线程共享内存(数据共享,共享全局变量),从而极大地提高了程序的运行效率。
    协程:是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和
    栈。 协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存
    器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切
    换非常快。
  2. 什么是多线程竞争?(2018-3-30-lxy)
    线程是非独立的,同一个进程里线程是数据共享的,当各个线程访问数据资源时会出现竞争状态即:
    数据几乎同步会被多个线程占用,造成数据混乱 ,即所谓的线程不安全
    那么怎么解决多线程竞争问题?-- 锁。
    锁的好处:
    确保了某段关键代码(共享数据资源)只能由一个线程从头到尾完整地执行能解决多线程资源竞争下
    的原子操作问题。
    锁的坏处:
    阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了
    锁的致命问题:死锁。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值