使用MongoDB管理Python多处理
我试图用多处理函数运行我的代码,但mongo不断返回 “MongoClient在fork之前打开。使用 connect=False,或在分叉后创建客户端。“ 我真的不明白我怎样才能使我的代码适应这个。 基本上,结构是:使用MongoDB管理Python多处理,python,mongodb,python-2.7,pymongo,python-multiprocessing,Python,Mongodb,Python 2.7,Pymongo,Python Multiprocessing,我试图用多处理函数运行我的代码,但mongo不断返回 “MongoClient在fork之前打开。使用 connect=False,或在分叉后创建客户端。“ 我真的不明白我怎样才能使我的代码适应这个。 基本上,结构是: db = MongoClient().database db.authenticate('user', 'password', mechanism='SCRAM-SHA-1') collectionW = db['words'] collectionT = db['sinMemo
db = MongoClient().database
db.authenticate('user', 'password', mechanism='SCRAM-SHA-1')
collectionW = db['words']
collectionT = db['sinMemo']
collectionL = db['sinLogic']
def findW(word):
rows = collectionw.find({"word": word})
ind = 0
for row in rows:
ind += 1
id = row["_id"]
if ind == 0:
a = ind
else:
a = id
return a
def trainAI(stri):
...
if findW(word) == 0:
_id = db['words'].insert(
{"_id": getNextSequence(db.counters, "nodeid"), "word": word})
story = _id
else:
story = findW(word)
...
def train(index):
# searching progress
progFile = "./train/progress{0}.txt".format(index)
trainFile = "./train/small_file_{0}".format(index)
if os.path.exists(progFile):
f = open(progFile, "r")
ind = f.read().strip()
if ind != "":
pprint(ind)
i = int(ind)
else:
pprint("No progress saved or progress lost!")
i = 0
f.close()
else:
i = 0
#get the number of line of the file
rangeC = rawbigcount(trainFile)
#fix unicode
non_bmp_map = dict.fromkeys(range(0x10000, sys.maxunicode + 1), 0xfffd)
files = io.open(trainFile, "r", encoding="utf8")
str1 = ""
str2 = ""
filex = open(progFile, "w")
with progressbar.ProgressBar(max_value=rangeC) as bar:
for line in files:
line = line.replace("\n", "")
if i % 2 == 0:
str1 = line.translate(non_bmp_map)
else:
str2 = line.translate(non_bmp_map)
bar.update(i)
trainAI(str1 + " " + str2)
filex.seek(0)
filex.truncate()
filex.write(str(i))
i += 1
#multiprocessing function
maxProcess = 3
def f(l, i):
l.acquire()
train(i + 1)
l.release()
if __name__ == '__main__':
lock = Lock()
for num in range(maxProcess):
pprint("start " + str(num))
Process(target=f, args=(lock, num)).start()
此代码用于在4个不同的进程中读取4个不同的文件,同时将数据插入数据库。
我只复制了部分代码,以便让您了解它的结构
我已尝试将connect=False添加到此代码中,但没有添加任何内容
db = MongoClient(connect=False).database
db.authenticate('user', 'password', mechanism='SCRAM-SHA-1')
collectionW = db['words']
collectionT = db['sinMemo']
collectionL = db['sinLogic']
然后我尝试在f函数中移动它(就在train()之前),但我得到的结果是程序没有找到collectionW、collectionT和collectionL
我不是python或mongodb的专家,所以我希望这不是一个愚蠢的问题
代码在Ubuntu 16.04.2下运行,带有python 2.7.12。authenticate必须连接到mongo服务器,并尝试建立连接。因此,即使使用connect=False,db.authenticate也需要打开连接。
为什么不在fork之后创建mongo客户端实例呢?这看起来是最简单的解决方案。因为
db.authenticate
必须打开MongoClient并连接到服务器,它会创建在fork子进程中不起作用的连接。因此,出现错误消息。请改为尝试以下操作:
db = MongoClient('mongodb://user:password@localhost', connect=False).database
另外,删除锁
l
。在一个子流程中获取锁对其他子流程没有影响。下面是我如何解决问题的:
import pathos.pools as pp
import time
import db_access
class MultiprocessingTest(object):
def __init__(self):
pass
def test_mp(self):
data = [[form,'form_number','client_id'] for form in range(5000)]
pool = pp.ProcessPool(4)
pool.map(db_access.insertData, data)
if __name__ == '__main__':
time_i = time.time()
mp = MultiprocessingTest()
mp.test_mp()
time_f = time.time()
print 'Time Taken: ', time_f - time_i
以下是db_access.py:
from pymongo import MongoClient
def insertData(form):
client = MongoClient()
db = client['TEST_001']
db.initialization.insert({
"form": form[0],
"form_number": form[1],
"client_id": form[2]
})
您的代码会出现这种情况,因为您要为所有子进程启动一次MongoCLient()。MongoCLient不是fork-safe。因此,在每个函数内部启动都有效,并让我知道是否有其他解决方案。这并不完全是一个新主题,因为“线程安全”的一般概念使用数据库连接已经存在很长时间了。可能是因为错误消息如此具有描述性和精确性。您被告知仅在分叉后建立连接,以便连接仅存在于工作进程中。如果您需要某种类型的IPC,则可以使用其他方法来完成此操作。但数据库句柄将被复制到een进程/线程是“正确的”,已经有很长一段时间了。但我到底该怎么做呢?这是我不明白的一点。你可以在目标函数f中创建mongo客户端。或者将创建mongo客户端的代码放在函数f将调用的函数中。我已经做了,但是,正如我在问题中所写的,我不知道如何处理这些函数它需要变量collectionW、collectionT和collectionL。他已经从主进程创建了锁。因此,它将同步子进程。但是同步子进程在这里看起来并不合适,因为它是一种大锁,无法实现使用子进程的目的。在一个子进程中获取锁ss对其他子进程没有影响。=)实际上,多处理锁(不是线程公开的锁)由信号量()支持,因此它们可以用于同步不同的进程。因此,如果其他进程也试图获取相同的锁,那么获取多处理锁将影响其他进程。这里有一个演示相同的要点哦,假设提问者使用的是一个多处理锁,那么你是对的,它有效果,这违背了使用子进程的目的。