python进阶03
进程线程不管哪门语言都是一块可以被重视的方向,下面一起学习学习python中的进程,线程
1.进程线程区别
通俗解释:一个程序QQ的运行就是一个进程运行;QQ中打开多个页面互不影响可以同时操作的每个页面的运作就是线程
专业解释:进程-担当系统分配资源(CPU时间,内存)基本单元;线程-程序执行的最小单元
2.进程
1)fork()
2.1.1:介绍
linux可以多进程操作,所以它能实现登录多个QQ;os模块封装了fork()方法能创建一个进程
操作系统会创建一个新的进程,复制父进程所有信息到子进程中;
fork()函数一定会得到一个返回值,子进程中为0,父进程中就是子进程的id号;
父进程要记下每个子进程的ID,而子进程只需要调用getppid()就可以拿到父进程的ID;
getpid():放回当前进程标识;getppid():返回父进程标识
2.1.2:用法
import os rpid = os.fork()
if rpid<:
print("fork调用失败。")
elif rpid == :
print("我是子进程(%s),我的父进程是(%s)"%(os.getpid(),os.getppid()))
x+=
else:
print("我是父进程(%s),我的子进程是(%s)"%(os.getpid(),rpid)) print("父子进程都可以执行这里的代码") 运行结果:
我是父进程(),我的子进程是()
父子进程都可以执行这里的代码
我是子进程(),我的父进程是()
父子进程都可以执行这里的代码
2)注意
多进程中所有数据(包括全局变量)都各有一份,互不影响
3)multiprocessing
2.3.1:介绍
跨平台的非linux支持的多进程模块,提供了一个Process类代表一个进程对象
2.3.2:Process-进程创建
Process([group [, target [, name [, args [, kwargs]]]]])
target:表示这个进程实例所调用对象;
args:表示调用对象的位置参数元组;
kwargs:表示调用对象的关键字参数字典;
name:为当前进程实例的别名;
group:大多数情况下用不到;
Process类常用方法:
is_alive():判断进程实例是否还在执行;
join([timeout]):是否等待进程实例执行结束,或等待多少秒;
start():启动进程实例(创建子进程);
run():如果没有给定target参数,对这个对象调用start()方法时,就将执行对象中的run()方法;
terminate():不管任务是否完成,立即终止;
Process类常用属性:
name:当前进程实例别名,默认为Process-N,N为从1开始递增的整数;
pid:当前进程实例的PID值;
2.3.3 例子
from multiprocessing import Process
import os
from time import sleep # 子进程要执行的代码
def run_proc(name, age, **kwargs):
for i in range():
print('子进程运行中,name= %s,age=%d ,pid=%d...' % (name, age,os.getpid()))
print(kwargs)
sleep(0.5) if __name__=='__main__':
print('父进程 %d.' % os.getpid())
p = Process(target=run_proc, args=('test',), kwargs={"m":})
print('子进程将要执行')
p.start()
sleep()
p.terminate()
p.join()
print('子进程已结束')
运行结果:
父进程 .
子进程将要执行
子进程运行中,name= test,age= ,pid=...
{'m': }
子进程运行中,name= test,age= ,pid=...
{'m': }
子进程已结束
2.3.4 Process子类-进程创建
创建新的进程还能够使用类的方式,可以自定义一个类,继承Process类
例子:
from multiprocessing import Process
import time
import os #继承Process类
class Process_Class(Process):
#因为Process类本身也有__init__方法,这个子类相当于重写了这个方法,
#但这样就会带来一个问题,我们并没有完全的初始化一个Process类,所以就不能使用从这个类继承的一些方法和属性,
#最好的方法就是将继承类本身传递给Process.__init__方法,完成这些初始化操作
def __init__(self,interval):
Process.__init__(self)
self.interval = interval #重写了Process类的run()方法
def run(self):
print("子进程(%s) 开始执行,父进程为(%s)"%(os.getpid(),os.getppid()))
t_start = time.time()
time.sleep(self.interval)
t_stop = time.time()
print("(%s)执行结束,耗时%0.2f秒"%(os.getpid(),t_stop-t_start)) if __name__=="__main__":
t_start = time.time()
print("当前程序进程(%s)"%os.getpid())
p1 = Process_Class()
#对一个不包含target属性的Process类执行start()方法,就会运行这个类中的run()方法,所以这里会执行p1.run()
p1.start()
p1.join()
t_stop = time.time()
print("(%s)执行结束,耗时%0.2f"%(os.getpid(),t_stop-t_start))
4)进程池
当子进程不多,直接用multprocessing中的Process动态生成多个进程,但如果是很多,手动创建工作量很大,此时就可以用multprocessing模块提供的pool方法了
运行机制:初始化进程池时可以指定最大进程数,当有新请求会先看进程池运行进程是否达到最大进程数,没有就创建一个进程放入进程池来维护同时运行子进程
multiprocessing.Pool常用函数解析:
apply_async(func[, args[, kwds]]) :使用非阻塞方式调用func(并行执行,堵塞方式必须等待上一个进程退出才能执行下一个进程),args为传递给func的参数列表,kwds为传递给func的关键字参数列表;
apply(func[, args[, kwds]]):使用阻塞方式调用func
close():关闭Pool,使其不再接受新的任务;
terminate():不管任务是否完成,立即终止;
join():主进程阻塞,等待子进程的退出, 必须在close或terminate之后使用;
例子:
from multiprocessing import Pool
import os,time,random def worker(msg):
t_start = time.time()
print("%s开始执行,进程号为%d"%(msg,os.getpid()))
#random.random()随机生成0~1之间的浮点数
time.sleep(random.random()*)
t_stop = time.time()
print(msg,"执行完毕,耗时%0.2f"%(t_stop-t_start)) po=Pool() #定义一个进程池,最大进程数3
for i in range(,):
#Pool.apply_async(要调用的目标,(传递给目标的参数元祖,))
#每次循环将会用空闲出来的子进程去调用目标
po.apply_async(worker,(i,)) print("----start----")
po.close() #关闭进程池,关闭后po不再接收新的请求
po.join() #等待po中所有子进程执行完成,必须放在close语句之后
print("-----end-----") 运行结果:
----start----
0开始执行,进程号为21466
1开始执行,进程号为21468
2开始执行,进程号为21467
执行完毕,耗时1.
3开始执行,进程号为21466
执行完毕,耗时1.
4开始执行,进程号为21467
执行完毕,耗时0.
5开始执行,进程号为21466
执行完毕,耗时1.
6开始执行,进程号为21468
执行完毕,耗时0.
7开始执行,进程号为21467
执行完毕,耗时0.
8开始执行,进程号为21466
执行完毕,耗时0.
9开始执行,进程号为21468
执行完毕,耗时1.
执行完毕,耗时1.
执行完毕,耗时1.
-----end-----
5)进程间的通信-Queue
Process之间有时也需要通信,操作系统提供了很多机制来实现进程间通信
2.5.1 Queue方法介绍
初始化Queue()对象时(例如:q=Queue()),若括号中没有指定最大可接收的消息数量,或数量为负值,那么就代表可接受的消息数量没有上限(直到内存的尽头); Queue.qsize():返回当前队列包含的消息数量; Queue.empty():如果队列为空,返回True,反之False ; Queue.full():如果队列满了,返回True,反之False; Queue.get([block[, timeout]]):获取队列中的一条消息,然后将其从列队中移除,block默认值为True;
例子
from multiprocessing import Process, Queue
import os, time, random # 写数据进程执行的代码:
def write(q):
for value in ['A', 'B', 'C']:
print 'Put %s to queue...' % value
q.put(value)
time.sleep(random.random()) # 读数据进程执行的代码:
def read(q):
while True:
if not q.empty():
value = q.get(True)
print 'Get %s from queue.' % value
time.sleep(random.random())
else:
break if __name__=='__main__':
# 父进程创建Queue,并传给各个子进程:
q = Queue()
pw = Process(target=write, args=(q,))
pr = Process(target=read, args=(q,))
# 启动子进程pw,写入:
pw.start()
# 等待pw结束:
pw.join()
# 启动子进程pr,读取:
pr.start()
pr.join()
# pr进程里是死循环,无法等待其结束,只能强行终止:
print ''
print '所有数据都写入并且读完'
2.5.2 进程池中的Queue
如果要使用Pool创建进程,就需要使用multiprocessing.Manager()中的Queue(),而不是multiprocessing.Queue()
例子
#coding=utf- #修改import中的Queue为Manager
from multiprocessing import Manager,Pool
import os,time,random def reader(q):
print("reader启动(%s),父进程为(%s)"%(os.getpid(),os.getppid()))
for i in range(q.qsize()):
print("reader从Queue获取到消息:%s"%q.get(True)) def writer(q):
print("writer启动(%s),父进程为(%s)"%(os.getpid(),os.getppid()))
for i in "dongGe":
q.put(i) if __name__=="__main__":
print("(%s) start"%os.getpid())
q=Manager().Queue() #使用Manager中的Queue来初始化
po=Pool()
#使用阻塞模式创建进程,这样就不需要在reader中使用死循环了,可以让writer完全执行完成后,再用reader去读取
po.apply(writer,(q,))
po.apply(reader,(q,))
po.close()
po.join()
print("(%s) End"%os.getpid())
2.线程
1)threading模块
通过这个模块将thread封装能更好操作
2.1.1 注意:
一个进程所有线程共享全局变量,但这可能会造成线程安全
2)锁
当多个线程同时修改同一个共享数据时,需要进行同步控制
创建方式
#创建锁
mutex = threading.Lock()
#锁定
mutex.acquire([blocking])
#释放
mutex.release()
例子
from threading import Thread, Lock
import time g_num = def test1():
global g_num
for i in range():
#True表示堵塞 即如果这个锁在上锁之前已经被上锁了,那么这个线程会在这里一直等待到解锁为止
#False表示非堵塞,即不管本次调用能够成功上锁,都不会卡在这,而是继续执行下面的代码
mutexFlag = mutex.acquire(True)
if mutexFlag:
g_num +=
mutex.release() print("---test1---g_num=%d"%g_num) def test2():
global g_num
for i in range():
mutexFlag = mutex.acquire(True) #True表示堵塞
if mutexFlag:
g_num +=
mutex.release() print("---test2---g_num=%d"%g_num) #创建一个互斥锁
#这个所默认是未上锁的状态
mutex = Lock() p1 = Thread(target=test1)
p1.start() p2 = Thread(target=test2)
p2.start() print("---g_num=%d---"%g_num)
锁好是好,但也可能造成死锁情况
局部变量是各个线程自己的非共享
3)TheadLocal
ThreadLocal解决了参数在一个线程中各个函数之间互相传递的问题
实实在在的解决了开发过程中的问题
用法:local_school = threading.local()
import threading # 创建全局ThreadLocal对象:
local_school = threading.local() def process_student():
# 获取当前线程关联的student:
std = local_school.student
print('Hello, %s (in %s)' % (std, threading.current_thread().name)) def process_thread(name):
# 绑定ThreadLocal的student:
local_school.student = name
process_student() t1 = threading.Thread(target= process_thread, args=('dongGe',), name='Thread-A')
t2 = threading.Thread(target= process_thread, args=('老王',), name='Thread-B')
t1.start()
t2.start()
t1.join()
t2.join()
python进阶03的更多相关文章
- python进阶03 继承
python进阶03 继承 一.继承 课堂练习:假设你正在参与一个魔幻类角色游戏的开发,公司需要腻味这个游戏设计两个角色的类: a.剑士 属性:1.角色名:2.角色等级:3.生命值:4.攻击力 行为: ...
- Python进阶03 模块
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 我们之前看到了函数和对象.从本质上来说,它们都是为了更好的组织已经有的程序,以方便 ...
- Python进阶量化交易专栏场外篇7- 装饰器计算代码时间
欢迎大家订阅<教你用 Python 进阶量化交易>专栏!为了能够提供给大家更轻松的学习过程,笔者在专栏内容之外已陆续推出一些手记来辅助同学们学习本专栏内容,目前已推出如下扩展篇: 在第一篇 ...
- python进阶11 正则表达式
python进阶11 正则表达式 一.概念 #正则表达式主要解决什么问题? #1.判断一个字符串是否匹配给定的格式,判断用户提交的又想的格式是否正确 #2.从一个字符串中按指定格式提取信息,抓取页面中 ...
- Python进阶:函数式编程实例(附代码)
Python进阶:函数式编程实例(附代码) 上篇文章"几个小例子告诉你, 一行Python代码能干哪些事 -- 知乎专栏"中用到了一些列表解析.生成器.map.filter.lam ...
- Python进阶 - 对象,名字以及绑定
Python进阶 - 对象,名字以及绑定 1.一切皆对象 Python哲学: Python中一切皆对象 1.1 数据模型-对象,值以及类型 对象是Python对数据的抽象.Python程序中所有的数据 ...
- Python进阶-继承中的MRO与super
Python进阶-继承中的MRO与super 写在前面 如非特别说明,下文均基于Python3 摘要 本文讲述Python继承关系中如何通过super()调用"父类"方法,supe ...
- Python进阶 - 命名空间与作用域
Python进阶 - 命名空间与作用域 写在前面 如非特别说明,下文均基于Python3 命名空间与作用于跟名字的绑定相关性很大,可以结合另一篇介绍Python名字.对象及其绑定的文章. 1. 命名空 ...
- python进阶学习笔记(一)
python进阶部分要学习的内容: 学习目标: 1.函数式编程 1.1,什么是函数式编程 函数式编程是一种抽象计算的编程模式 不同语言的抽象层次不同: 函数式编程的特点: python支持的函数式编程 ...
随机推荐
- < 转载 > 说说JSON和JSONP
推荐博文---说说JSON和JSONP,也许你会豁然开朗,含jQuery用例 里头说的很详细!
- jqgrid 事件说明
Events(事件) 事件响应动作被设置为表格的属性,以下定义了行被选中时的响应: var lastSel; jQuery("#gridid").jqGrid({ ... o ...
- Java Modifier
- A Secret(KMP)
A Secret Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 256000/256000 K (Java/Others)Total ...
- E - Rails (栈)
E - Rails Time Limit:3000MS Memory Limit:0KB 64bit IO Format:%lld & %llu Description The ...
- linux磁盘清理
一.背景: 1.由于linux系统空间是由挂载磁盘得来的,但有时装系统时挂载/根目录空间不大,现仅清除用户下载的大文件 二.方法: 1.输入命令df -h显示当前磁盘挂载(包含剩余空间)情况这里写图片 ...
- GPU instancing
参考 https://www.cnblogs.com/hont/p/7143626.html github地址 https://github.com/yingsz/instancing/ 补充2点: ...
- Laravel 出现"RuntimeException inEncrypter.php line 43: The only supported ciphers are AES-128-CBC and AES-256-CBC with the correct key lengths."问题的解决办法
如果输入命令:php artisan key:generate 还是报错 那就要从别的项目里复制一个key到.env中,然后再运行命令:composer update和php artisan key: ...
- Andrew Ng机器学习编程作业: Linear Regression
编程作业有两个文件 1.machine-learning-live-scripts(此为脚本文件方便作业) 2.machine-learning-ex1(此为作业文件) 将这两个文件解压拖入matla ...
- 运行scrapy保存图片,报错ValueError: Missing scheme in request url: h
查阅相关资料,了解到使用ImagesPipeline传入的url地址必须是一个list,而我写的是一个字符串,所以报错,所以需要修改一下传入的url格式就行了 def parse_detail(sel ...