Python提供了非常好用的多进程包multiprocessing,你只需要定义一个函数,Python会替你完成其他所有事情.借助这个包,可以轻松完成从单进程到并发执行的转换.
①.、新建单一进程
如果我们新建少量进程,可以如下:
import multiprocessing
import time
def func(msg):
print msg
time.sleep(1)
if __name__ == "__main__":
p = multiprocessing.Process(target=func, args=("hello", ))
p.start()
p.join()
基于官方文档:
日乐购,刚才看到的一个博客,写的都不太对,还是基于官方的比较稳妥
我就是喜欢抄官方的,哈哈
通常我们使用Process实例化一个进程,并调用 他的 start() 方法启动它.
这种方法和 Thread 是一样的.
上图中,我写了 p.join() 所以主进程是 等待 子进程执行完后,才执行 print("运行结束")
否则就是反过来了(这个不一定,看你的语句了,顺序其实是随机的)例如:
主进加个 sleep
所以不加join() ,其实子进程和主进程是各干各的,谁也不等谁.都执行完后,文件运行就结束了
上面我们用了 os.getpid() 和 os.getppid() 获取 当前进程,和父进程的id
下面就讲一下,这两个函数的用法:
os.getpid()
返回当前进程的id
os.getppid()
返回父进程的id. 父进程退出后,unix 返回初始化进程(1)中的一个
windows返回相同的id (可能被其他进程使用了)
视频笔记:
多进程:使用大致方法:
参考: 进程通信(pipe和queue)
pool.map (函数可以有return 也可以共享内存或queue) 结果直接是个列表
poll.apply_async() (同map,只不过是一个进程,返回结果用 xx.get() 获得)
报错:
参考 :
把 pool = Pool() 放到 if name == " main ": 下面初始化搞定.
结果:
这个肯定有解释的
测试多进程计算效果:
进程池运行:
普通计算:
其实对比下来开始快了一半的;
我们把循环里的数字去掉一个 0;
单进程:
多进程:
问题 二:
视图:
post 视图里面
Music 类:
直接报错:
写在 类里面也 在函数里用 self.pool 调用也不行,也是相同的错误.
最后 把 pool = Pool 直接写在 search 函数里面,奇迹出现了:
前台也能显示搜索的音乐结果了
总结一点,进程这个东西,最好 写在 直接运行的函数里面,而不是 一个函数跳来跳去.因为最后可能 是在子进程的子进程运行的,这是不许的,会报错.
还有一点,多进程运行的函数对象,不能是 lambda 函数.也许lambda 虚拟,在内存?
使用 pool.map 子进程 函数报错,导致整个 pool 挂了:
参考:
主要你要,对函数内部捕获错误,而不能让异常抛出就可以了.
关于map 传多个函数参数
我一开始,就是正常思维,多个参数,搞个元祖,让参数一一对应不就行了:
普通的 process 当让可以穿多个参数,map 却不知道咋传的.
apply_async 和map 一样,不知道咋传的.
最简单的方法:
使用 starmap 而不是 map
子进程结束
成功拿到结果了
关于map 和 starmap 不同的地方看源码:
关于apply_async() ,我没找到多参数的方法,大不了用 一个迭代的 starmap 实现.哈哈
关于 上面源码里面有 itertools.starmap
itertools 用法参考:
有个问题,多进程最好不要使用全部的 cpu , 因为这样可能影响其他任务,所以 在进程池 添加 process 参数 指定,cpu 个数:
上面就是预留了 一个cpu 干其他事的
后面直接使用 Queue 遇到这个问题:
解决:
Manager().Queue() 代替 Queue()
因为 queue.get() 是堵塞型的,所以可以提前判断是不是 空的,以免堵塞进程.比如下面这样:
使用 queue.empty() 空为True
并发和并行
你吃饭吃到一半,电话来了,你一直到吃完了以后才去接,这就说明你不支持并发也不支持并行.
你吃饭吃到一半,电话来了,你停了下来接了电话,接完后继续吃饭,这说明你支持并发.
你吃饭吃到一半,电话来了,你一边打电话一边吃饭,这说明你支持并行.
并发的关键是你有处理多个任务的能力,不一定要同时.
并行的关键是你有同时处理多个任务的能力.
所以我认为它们最关键的点就是:是否是『同时』.
Python 中没有真正的并行,只有并发
无论你的机器有多少个CPU, 同一时间只有一个Python解析器执行.这也和大部分解释型语言一致, 都不支持并行.这应该是python设计的先天缺陷.
javascript也是相同的道理, javascript早起的版本只支持单任务,后来通过worker来支持并发.
Python中的多线程
先复习一下进程和线程的概念
所谓进程,简单的说就是一段程序的动态执行过程,是系统进行资源分配和调度的一个基本单位.一个进程中又可以包含若干个独立的执行流,我们将这些执行流称为线程,线程是CPU调度和分配的基本单位.同一个进程的线程都有自己的专有寄存器,但内存等资源是共享的.
Python中的thread的使用
通过 thread.start_new_thread 方法
import thread
# Define a function for the thread
def print_time( threadName, delay):
count = 0
time.sleep(delay)
count += 1
print "%s: %s" % ( threadName, time.ctime(time.time()) )
# Create two threads as follows
try:
except:
print "Error: unable to start thread"
while 1:
pass
通过继承thread
#!/usr/bin/python
import threading
exitFlag = 0
class myThread (threading.Thread):
def __init__(self, threadID, name, counter):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.counter = counter
def run(self):
print "Starting " + self.name
print "Exiting " + self.name
def print_time(threadName, delay, counter):
while counter:
if exitFlag:
threadName.exit()
print "%s: %s" % (threadName, time.ctime(time.time()))
counter -= 1
# Create new threads
thread1 = myThread(1, "Thread-1", 1)
# Start new Threads
thread1.start()
print "Exiting Main Thread"
线程的同步
# Get lock to synchronize threads
threadLock.acquire()
# Free lock to release next thread
threadLock.release()
threadLock = threading.Lock()
threads = []
# Add threads to thread list
threads.append(thread1)
# Wait for all threads to complete
for t in threads:
t.join()
利用multiprocessing多进程实现并行
进程的创建
Python 中有一套类似多线程API 的的类来进行多进程开发: multiprocessing
这里是一个来自官方文档的例子:
from multiprocessing import Process
def f(name):
print 'hello', name
if __name__ == '__main__':
p = Process(target=f, args=('bob',))
类似与线程,一可以通过继承process类来实现:
class Worker(Process):
print("in" + self.name)
jobs = []
p = Worker()
jobs.append(p)
for j in jobs:
j.join()
进程的通信
Pipe()
pipe()函数返回一对由双向通信的管道连接的对象,这两个对象通过send, recv 方法实现 信息的传递
from multiprocessing import Process, Pipe
def f(conn):
conn.close()
parent_conn, child_conn = Pipe()
p = Process(target=f, args=(child_conn,))
Quene
from multiprocessing import Process, Queue
def f(q):
q = Queue()
p = Process(target=f, args=(q,))
进程间的同步
Python 中多进程中也有类似线程锁的概念,使用方式几乎一样:
from multiprocessing import Process, Lock
def f(l, i):
l.acquire()
print 'hello world', i
l.release()
lock = Lock()
for num in range(10):
Process(target=f, args=(lock, num)).start()
进程间的共享内存
每个进程都有独自的内存,是不能相互访问的, 也行 python官方觉得通过进程通信的方式过于麻烦,提出了共享内存的概念,以下是官方给出的例子:
from multiprocessing import Process, Value, Array
def f(n, a):
for i in range(len(a)):
a[i] = -a[i]
num = Value('d', 0.0)
arr = Array('i', range(10))
p = Process(target=f, args=(num, arr))
print num.value
print arr[:]
总结
python通过多进程实现多并行,充分利用多处理器,弥补了语言层面不支持多并行的缺点.Python, Node.js等解释型语言似乎都是通过这种方式来解决同一个时间,一个解释器只能处理一段程序的问题, 十分巧妙.
Linux中进程的通信方式有信号,管道,共享内存,消息队列socket等.其中管道是*nix系统进程间通信的最古老形式,所有*nix都提供这种通信方式.管道是一种半双工的通信机制,也就是说,它只能一端用来读,另外一端用来写;另外,管道只能用来在具有公共祖先的两个进程之间通信.管道通信遵循先进先出的原理,并且数据只能被读取一次,当此段数据被读取后,马上会从数据中消失,这一点很重要.
Linux上,创建管道使用pipe函数,当它执行后,会产生两个文件描述符,分别为读端和写端.单个进程中的管道几乎没有任何作用,通常会先调用pipe,然后调用fork,从而创建从父进程到子进程的IPC通道.
Linux中,我们经常会使用到管道,例如用cat命令查看一个大文件时,一页不能全部显示,我们可以通过cat xxx | more来分页显示,又比如搜索文件里的内容可以用 cat xxx | grep search来进行,这里我们都用到了管道.此时此刻呢我会用python编写一段自动分页显示的程序,而不用手动来使用管道.
#!/usr/bin/env python
import os,sys
if not sys.argv[1:]:
print "No filename input"
sys.exit(1)
fp = open(sys.argv[1],"r")
except IOError,msg:
sys.exit(msg)
pi=os.pipe()
pid=os.fork()
if pid:
#parent
os.close(pi[0]) #close read pipe
#write to pipe
line=fp.readline()
while line:
os.write(pi[1],line)
#close write pipe
os.close(pi[1])
#wait for chile
os.waitpid(pid,0)
else:
os.close(pi[1]) #close write pipe
#put pipe read to stdin
os.close(pi[0])
os.execl("/bin/more","more")
运算
b = 10
c = 0
c = a + b
print "1 - c 的值为:", c
c = a - b
c = a * b
c = a / b
c = a % b
c = a**b
a = 10
c = a//b
python比较
if ( a == b ):
print "1 - a 等于 b"
print "1 - a 不等于 b"
if ( a != b ):
if ( a b ):
if ( a = b ):
if ( b = a ):
赋值
c += a
c *= a
c /= a
c %= a
c **= a
c //= a
逻辑运算符:
if ( a and b ):
print "1 - 变量 a 和 b 都为 true"
print "1 - 变量 a 和 b 有一个不为 true"
if ( a or b ):
a = 0
if not( a and b ):
in,not in
if ( a in list ):
print "1 - 变量 a 在给定的列表中 list 中"
print "1 - 变量 a 不在给定的列表中 list 中"
if ( b not in list ):
条件
flag = False
name = 'luren'
if name == 'python': # 判断变量否为'python'
flag = True # 条件成立时设置标志为真
print 'welcome boss' # 并输出欢迎信息
print name
print 'boss'
print 'user'
elif num == 1:
print 'worker'
elif num 0: # 值小于零时输出
print 'error'
print 'roadman' # 条件均不成立时输出
循环语句:
print 'The count is:', count
count = count + 1
print "Good bye!"
i = 1
while i 10:
i += 1
continue
while 1: # 循环条件为1必定成立
print i # 输出1~10
if i 10: # 当i大于10时跳出循环
break
for letter in 'Python': # 第一个实例
print '当前字母 :', letter
fruits = ['banana', 'apple', 'mango']
for fruit in fruits: # 第二个实例
print '当前水果 :', fruit
获取用户输入:raw_input
var = 1
while var == 1 : # 该条件永远为true,循环将无限执行下去
num = raw_input("Enter a number :")
print "You entered: ", num
range,len
for index in range(len(fruits)):
print '当前水果 :', fruits[index]
python数学函数:
abs,cell,cmp,exp,fabs,floor,log,log10,max,min,mod,pow,round,sqrt
randrange
访问字符串的值
var1 = 'Hello World!'
print "var1[0]: ", var1[0]
转义字符
格式化输出
字符串函数:
添加元素
list = [] ## 空列表
list.append('Google') ## 使用 append() 添加元素
list.append('Runoob')
print list
删除元素
print list1
列表操作
列表方法
删除字典
del dict['Name']; # 删除键是'Name'的条目
dict.clear(); # 清空词典所有条目
del dict ; # 删除词典
print "dict['Age']: ", dict['Age'];
print "dict['School']: ", dict['School'];
字典的函数:
当前时间戳:
time.time()
格式化日期输出
print time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
print time.strftime("%a %b %d %H:%M:%S %Y", time.localtime())
print time.mktime(time.strptime(a,"%a %b %d %H:%M:%S %Y"))
获取某个月日历:calendar
import calendar
print cal
当前日期和时间
import datetime
i = datetime.datetime.now()
print ("当前的日期和时间是 %s" % i)
print ("ISO格式的日期和时间是 %s" % i.isoformat() )
print ("当前的年份是 %s" %i.year)
print ("当前的月份是 %s" %i.month)
print ("当前的日期是 %s" %i.day)
print ("dd/mm/yyyy 格式是 %s/%s/%s" % (i.day, i.month, i.year) )
print ("当前小时是 %s" %i.hour)
print ("当前分钟是 %s" %i.minute)
print ("当前秒是 %s" %i.second)
不定长参数:*
lambda:匿名函数
def....
python模块搜索路径
获取用户输入
str = raw_input("请输入:")
print "你输入的内容是: ", str
input可以接收表达式
open参数
write要自己添加换行符
读取10个字符
重命名:os.rename
os.remove
os.mkdir os.chdir
os.getcwd
os.rmdir
file的方法
异常:
fh = open("testfile", "w")
fh.write("这是一个测试文件,用于测试异常!!")
except IOError:
print "Error: 没有找到文件或读取文件失败"
print "内容写入文件成功"
fh.close()
finally:
用户自定义异常:
os 模块提供了非常丰富的方法用来处理文件和目录.常用的方法如下表所示:
| 序号 | 方法及描述 |
| 1 |
os.access(path, mode)
检验权限模式 |
os.chdir(path)
改变当前工作目录 |
os.chflags(path, flags)
设置路径的标记为数字标记. |
os.chmod(path, mode)
更改权限 |
os.chown(path, uid, gid)
更改文件所有者 |
os.chroot(path)
改变当前进程的根目录 |
os.close(fd)
关闭文件描述符 fd |
os.closerange(fd_low, fd_high)
关闭所有文件描述符,从 fd_low (包含) 到 fd_high (不包含), 错误会忽略 |
os.dup(fd)
复制文件描述符 fd |
| 10 |
| 11 |
os.fchdir(fd)
通过文件描述符改变当前工作目录 |
os.fchmod(fd, mode)
改变一个文件的访问权限,该文件由参数fd指定,参数mode是Unix下的文件访问权限. |
os.fchown(fd, uid, gid)
修改一个文件的所有权,这个函数修改一个文件的用户ID和用户组ID,该文件由文件描述符fd指定. |
os.fdatasync(fd)
强制将文件写入磁盘,该文件由文件描述符fd指定,但是不强制更新文件的状态信息. |
os.fdopen(fd[, mode[, bufsize]])
通过文件描述符 fd 创建一个文件对象,并返回这个文件对象 |
os.fpathconf(fd, name)
os.fstat(fd)
返回文件描述符fd的状态,像stat(). |
os.fstatvfs(fd)
返回包含文件描述符fd的文件的文件系统的信息,像 statvfs() |
os.fsync(fd)
强制将文件描述符为fd的文件写入硬盘. |
os.ftruncate(fd, length)
裁剪文件描述符fd对应的文件, 所以它最大不能超过文件大小. |
os.getcwd()
返回当前工作目录 |
os.getcwdu()
返回一个当前工作目录的Unicode对象 |
os.isatty(fd)
如果文件描述符fd是打开的,同时与tty(-like)设备相连,则返回true, 否则False. |
os.lchflags(path, flags)
设置路径的标记为数字标记,类似 chflags(),但是没有软链接 |
os.lchmod(path, mode)
修改连接文件权限 |
os.lchown(path, uid, gid)
更改文件所有者,类似 chown,但是不追踪链接. |
os.link(src, dst)
创建硬链接,名为参数 dst,指向参数 src |
os.listdir(path)
返回path指定的文件夹包含的文件或文件夹的名字的列表. |
os.lseek(fd, pos, how)
os.lstat(path)
像stat(),但是没有软链接 |
os.major(device)
从原始的设备号中提取设备major号码 (使用stat中的st_dev或者st_rdev field). |
os.makedev(major, minor)
以major和minor设备号组成一个原始设备号 |
os.makedirs(path[, mode])
递归文件夹创建函数.像mkdir(), 但创建的所有intermediate-level文件夹需要包含子文件夹. |
os.minor(device)
从原始的设备号中提取设备minor号码 (使用stat中的st_dev或者st_rdev field ). |
os.mkdir(path[, mode])
os.mkfifo(path[, mode])
创建一个名为filename文件系统节点(文件,设备特别文件或者命名pipe).
|
os.open(file, flags[, mode])
打开一个文件,并且设置需要的打开选项,mode参数是可选的 |
os.openpty()
打开一个新的伪终端对.返回 pty 和 tty的文件描述符. |
os.pathconf(path, name)
返回相关文件的系统配置信息. |
os.pipe()
创建一个管道. 返回一对文件描述符(r, w) 分别为读和写 |
os.popen(command[, mode[, bufsize]])
从一个 command 打开一个管道 |
os.read(fd, n)
从文件描述符 fd 中读取最多 n 个字节,返回包含读取字节的字符串,文件描述符 fd对应文件已达到结尾, 返回一个空字符串. |
os.readlink(path)
返回软链接所指向的文件 |
os.remove(path)
删除路径为path的文件.如果path 是一个文件夹,将抛出OSError; 查看下面的rmdir()删除一个 directory. |
os.removedirs(path)
递归删除目录. |
os.rename(src, dst)
重命名文件或目录,从 src 到 dst |
os.renames(old, new)
递归地对目录进行更名,也可以对文件进行更名. |
os.rmdir(path)
删除path指定的空目录,如果目录非空,则抛出一个OSError异常. |
os.stat(path)
获取path指定的路径的信息,功能等同于C API中的stat()系统调用. |
os.stat_float_times([newvalue])
决定stat_result是否以float对象显示时间戳
os.statvfs(path)
获取指定路径的文件系统统计信息 |
os.symlink(src, dst)
创建一个软链接 |
os.tcgetpgrp(fd)
返回与终端fd(一个由os.open()返回的打开的文件描述符)关联的进程组 |
os.tcsetpgrp(fd, pg)
设置与终端fd(一个由os.open()返回的打开的文件描述符)关联的进程组为pg. |
os.tempnam([dir[, prefix]])
返回唯一的路径名用于创建临时文件. |
os.tmpfile()
返回一个打开的模式为(w+b)的文件对象 .这文件对象没有文件夹入口,没有文件描述符,将会自动删除. |
os.tmpnam()
为创建一个临时文件返回一个唯一的路径 |
os.ttyname(fd)
返回一个字符串,它表示与文件描述符fd 关联的终端设备.如果fd 没有与终端设备关联,则引发一个异常. |
os.unlink(path)
删除文件路径 |
os.utime(path, times)
返回指定的path文件的访问和修改的时间. |
os.walk(top[, topdown=True[, onerror=None[, followlinks=False]]])
输出在文件夹中的文件名通过在树中游走,向上或者向下. |
os.write(fd, str)
写入字符串到文件描述符 fd中. 返回实际写入的字符串长度 |
以上就是土嘎嘎小编为大家整理的pipe函数python相关主题介绍,如果您觉得小编更新的文章只要能对粉丝们有用,就是我们最大的鼓励和动力,不要忘记讲本站分享给您身边的朋友哦!!