python 使用multiprocessing需要注意的问题
我们在编写程序的时候经常喜欢这样写代码
import MySQLdb
import time
from multiprocessing import Process
conn = MySQLdb.connect(‘localhost‘, ‘vearne‘, ‘xx‘, ‘test‘)
def f(name):
for i in xrange(10):
cursor = conn.cursor()
sql = "insert into car(name) values(%s)"
param = [(name)]
print param
#time.sleep(1)
n = cursor.execute(sql,param)
cursor.close()
conn.commit()
if __name__ == ‘__main__‘:
for i in xrange(10):
p = Process(target=f, args=(‘bob‘,))
p.start()
上面的程序有问题吗?
以上的程序在单进程的情况下,应该是没有问题,但是在多进程的情况下,它是有错误的。
首先看看下面的源码
class Process(object):
‘‘‘
Process objects represent activity that is run in a separate process
The class is analagous to `threading.Thread`
‘‘‘
_Popen = None
def __init__(self, group=None, target=None, name=None, args=(), kwargs={}):
assert group is None, ‘group argument must be None for now‘
count = _current_process._counter.next()
self._identity = _current_process._identity + (count,)
self._authkey = _current_process._authkey
self._daemonic = _current_process._daemonic
self._tempdir = _current_process._tempdir
self._parent_pid = os.getpid()
self._popen = None
self._target = target
self._args = tuple(args)
self._kwargs = dict(kwargs)
self._name = name or type(self).__name__ + ‘-‘ + ‘:‘.join(str(i) for i in self._identity)
def run(self):
‘‘‘
Method to be run in sub-process; can be overridden in sub-class
‘‘‘
if self._target:
self._target(*self._args, **self._kwargs)
def start(self):
‘‘‘
Start child process
‘‘‘
assert self._popen is None, ‘cannot start a process twice‘
assert self._parent_pid == os.getpid(), ‘can only start a process object created by current process‘
assert not _current_process._daemonic, ‘daemonic processes are not allowed to have children‘
_cleanup()
if self._Popen is not None:
Popen = self._Popen
else:
from .forking import Popen
self._popen = Popen(self) # -- 创建 Popen 对象 --
_current_process._children.add(self)
# 省略部分代码 ... ...
def _bootstrap(self): # -- _bootstrap 函数 --
from . import util
global _current_process
try:
self._children = set()
self._counter = itertools.count(1)
try:
sys.stdin.close()
sys.stdin = open(os.devnull)
except (OSError, ValueError):
pass
_current_process = self
util._finalizer_registry.clear()
util._run_after_forkers()
util.info(‘child process calling self.run()‘)try:self.run()# -- 调用run函数 --
exitcode =0finally:
util._exit_function()exceptSystemExit, e:ifnot e.args:
exitcode =1elif isinstance(e.args[0],int):
exitcode = e.args[0]else:
sys.stderr.write(str(e.args[0])+‘\n‘)
sys.stderr.flush()
exitcode =0if isinstance(e.args[0], str)else1except:
exitcode =1import traceback
sys.stderr.write(‘Process%s:\n‘%self.name)
sys.stderr.flush()
traceback.print_exc()
util.info(‘process exiting with exitcode %d‘% exitcode)return exitcode
from .forking import Popen 定义
class Popen(object):
def __init__(self, process_obj):
sys.stdout.flush()
sys.stderr.flush()
self.returncode = None
self.pid = os.fork() # -- fork子进程 --
# fork 函数调用一次,会在返回两次,一次在父进程中返回,返回的pid 值大于0
# 一次在子进程中返回,返回的pid值 等于 0
if self.pid == 0: # pid值 等于 0 说明 以下代码都是在子进程中执行的
if ‘random‘ in sys.modules:
import random
random.seed()
code = process_obj._bootstrap() # -- 调用_bootstrap函数 --
sys.stdout.flush()
sys.stderr.flush()
os._exit(code)
从代码中我们可以看出,python 的multiprocessing 使用fork创建子进程,并在子进程中执行run函数
man fork
可以得到如下信息
Fork() causes creation of a new process. The new process (child process) is an exact copy of the calling process (parent process) except for the following:
o The child process has a unique process ID.
o The child process has a different parent process ID (i.e., the process ID of the parent process).
o The child process has its own copy of the parent‘s descriptors. These descriptors reference the same underlying objects, so that, for instance, file pointers in file objects are shared between the child and the parent, so that an lseek(2) on a descriptor in the child process can affect a subsequent read or write by the parent. This descriptor copying is also used by the shell to establish standard input and output for newly created processes as well as to set up pipes.
o The child processes resource utilizations are set to 0; see setrlimit(2).
fork 函数创建的子进程是父进程的完全拷贝,他们拥有相同的文件描述符。这样如果在父进程中创建了连接,就会出现父进程和多个子进程公用一个连接,会出现无法预料的错误。
(每个连接都有独立的读缓冲区和写缓冲区,多个进程的对读缓冲区和写缓冲区的操作会导致数据混乱)
所以我们应该在子进程中创建连接,这样就能够避免问题的发生。
import MySQLdb
import time
from multiprocessing import Process
class SLWorker(Process):
def __init__(self):
super(SLWorker, self).__init__()
self.conn = None
def run(self):
# *** 注意这里 *** 连接延迟加载, 也就是说连接在子进程中被创建
if self.conn == None:
self.conn = MySQLdb.connect(‘localhost‘, ‘vearne‘, ‘xxx‘, ‘test‘)
for i in xrange(10):
cursor = self.conn.cursor()
sql = "insert into car(name) values(%s)"
name = "bob"
param = [(name)]
print param
#time.sleep(30)
n = cursor.execute(sql,param)
cursor.close()
self.conn.commit()
def __del__(self):
if self.conn != None:
self.conn.close()
if __name__ == ‘__main__‘:
ll = []
for i in xrange(10):
p = SLWorker()
p.start()
ll.append(p)
for p in ll:
p.join()
答案归结为只需要将在子进程中创建连接,或者连接延迟创建就能够解决这个问题
其实现在有很多连接池都是延迟创建连接,没有仔细看,有研究的分享下。
PS: celery 和rq 也都会有这样的问题,请大家引起足够重视
版权声明:本文为博主原创文章,未经博主允许不得转载。
python 使用multiprocessing需要注意的问题
原文地址:http://blog.csdn.net/woshiaotian/article/details/46892689
python 使用multiprocessing需要注意的问题的更多相关文章
- python中multiprocessing.pool函数介绍_正在拉磨_新浪博客
python中multiprocessing.pool函数介绍_正在拉磨_新浪博客 python中multiprocessing.pool函数介绍 (2010-06-10 03:46:5 ...
- python的multiprocessing模块进程创建、资源回收-Process,Pool
python的multiprocessing有两种创建进程的方式,每种创建方式和进程资源的回收都不太相同,下面分别针对Process,Pool及系统自带的fork三种进程分析. 1.方式一:fork( ...
- python之multiprocessing创建进程
python的multiprocessing模块是用来创建多进程的,下面对multiprocessing总结一下使用记录. multiprocessing创建多进程在windows和linux系统下的 ...
- python多进程-----multiprocessing包
multiprocessing并非是python的一个模块,而是python中多进程管理的一个包,在学习的时候可以与threading这个模块作类比,正如我们在上一篇转载的文章中所提,python的多 ...
- python多进程(multiprocessing)
最近有个小课题,需要用到双进程,翻了些资料,还算圆满完成任务.记录一下~ 1.简单地双进程启动 同时的调用print1()和print2()两个打印函数,代码如下: #/usr/bin/python ...
- Python使用multiprocessing实现一个最简单的分布式作业调度系统
Python使用multiprocessing实现一个最简单的分布式作业调度系统介绍Python的multiprocessing模块不但支持多进程,其中managers子模块还支持把多进程分布到多台机 ...
- python多进程multiprocessing Pool相关问题
python多进程想必大部分人都用到过,可以充分利用多核CPU让代码效率更高效. 我们看看multiprocessing.pool.Pool.map的官方用法 map(func, iterable[, ...
- Shared variable in python's multiprocessing
Shared variable in python's multiprocessing https://www.programcreek.com/python/example/58176/multip ...
- python下multiprocessing和gevent的组合使用
python下multiprocessing和gevent的组合使用 对于有些人来说Gevent和multiprocessing组合在一起使用算是个又高大上又奇葩的工作模式. Python的多线程受制 ...
随机推荐
- Django实现的博客系统中使用富文本编辑器ckeditor
操作系统为OS X 10.9.2,Django为1.6.5. 1.下载和安装 1.1 安装 ckeditor 下载地址 https://github.com/shaunsephton/django-c ...
- asp.net core系列 65 正反案例介绍SOLID原则
一.概述 SOLID五大原则使我们能够管理解决大多数软件设计问题.由Robert C. Martin在20世纪90年代编写了这些原则.这些原则为我们提供了从紧耦合的代码和少量封装转变为适当松耦合和封装 ...
- T1229 数字游戏 codevs
http://codevs.cn/problem/1229/ 题目描述 Description Lele 最近上课的时候都很无聊,所以他发明了一个数字游戏来打发时间. 这个游戏是这样的,首先,他拿出 ...
- 解决Eclipse中SVN版本信息不显示的问题
eclipse 中使用 svn 插件,原本正常,未作任何更改,最近几天突然eclipse 中查看文件时,文件后面的 版本号 . 文件的状态图标 等等都不见了.以为有插件冲突,卸载了好多其他的相关的插 ...
- 【spring boot Mybatis】报错:org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.newhope.interview.dao.UserMapper.add
报错如下: org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.newhope.i ...
- vim列块操作
一.可视模式 进入可视模式有三种方法:v,V,CTRL+V (1)按v启用可视模式,能够按单个字符选择内容,移动光标能够选择. 如: (2)按V启用可视模式,立马选中光标所在行.按单行符选择内容.移动 ...
- UVA 1356 - Bridge(自适应辛普森)
UVA 1356 - Bridge option=com_onlinejudge&Itemid=8&page=show_problem&category=493&pro ...
- Python 模块的安装与使用
我们知道使用函数不仅减轻了工作量,而且使代码更加简洁,更加的易于维护.但如果在另一个文件中,我们希望使用上一个文件中定义的某个函数,我们应该怎么办呢?我们需要重新将上一个函数再次实现一遍吗?而且,当我 ...
- mysql有哪几种索引
从数据结构角度 1. B+树索引(O(log(n))) 2. hash索引 3. FULLTEXT索引 4. R-Tree索引 从物理存储角度 1. 聚集索引 2. 非聚集索引 从逻辑角度 ...
- Swift中字符串转化为Class的方法
Swift中字符串转化为Class的方法 在开发中有时候会根据字符串进行对应类的转化,这样我们就可以动态根据服务器返回的字段,动态的加载类,比如优酷,微博等APP会在节假日等动态的TabBar.这样可 ...