그래서 기본적으로 80GB 이상의 파일을 작성하는 Python 스크립트가 있습니다. 현재는 순차적으로 실행되며 실제로 서버를 실행할 때만 약 13 시간이 걸립니다.파이썬 멀티 스레딩 성능 - 대신 C++ 사용?
필자는 병렬화하여 하나가 아닌 많은 파일을 씁니다.
내가 이미 가지고있는 것을 파이썬에서 유지하는 것이 약간 쉬울 것이지만 다중 스레드를 통합 할 것입니다 (액세스 할 필요가있는 공유 데이터의 단일 맵이 있습니다. 그래서 아무도 쓰지 않을 것입니다. t 보호가 필요함).
그러나 파이썬에서 유지하는 것은 어리석은가요? 나는 C++도 알고 있으므로 C++로 다시 작성해야한다고 생각합니까? 나는이 프로그램이 다른 어떤 것보다 더 많은 디스크에 묶여 있다는 것을 알 수있다. (파일을 쓰는 데 사용 된 톤이 없다.) 아마 차이가별로 없을 것이다. 나는 C + +가 똑같은 80GB 파일을 (연속적으로) 쓰는 데 얼마나 오래 걸릴지는 잘 모르겠다.
UPDATE 6/6/14, 태평양 표준시 16시 40분 : 나는 그것이 순전히 디스크 바운드되는 반대로 코드 자체에 병목 현상이 있는지 확인하기 위해 아래에있는 내 코드를 게시하고있다.
약 30 개의 테이블이있는 테이블 당 한 번 writeEntriesToSql()을 호출합니다. "size"는 테이블에 기록 할 삽입 수입니다. 모든 테이블의 누적 크기는 약 200,000,000입니다.
나는 내가 얼마나 많은 낭비가 될지 모르겠지만, 내 정규 표현식을 반복해서 컴파일하고 있음을 알았다.
def writeEntriesToSql(db, table, size, outputFile):
# get a description of the table
rows = queryDatabaseMultipleRows(db, 'DESC ' + table)
fieldNameCol = 0 # no enums in python 2.7 :(
typeCol = 1
nullCol = 2
keyCol = 3
defaultCol = 4
extraCol = 5
fieldNamesToTypes = {}
for row in rows:
if (row[extraCol].find("auto_increment") == -1):
# insert this one
fieldNamesToTypes[row[fieldNameCol]] = row[typeCol]
for i in range(size):
fieldNames = ""
fieldVals = ""
count = 0
# go through the fields
for fieldName, type in fieldNamesToTypes.iteritems():
# build a string of field names to be used in the INSERT statement
fieldNames += table + "." + fieldName
if fieldName in foreignKeys[table]:
otherTable = foreignKeys[table][fieldName][0]
otherTableKey = foreignKeys[table][fieldName][1]
if len(foreignKeys[table][fieldName]) == 3:
# we already got the value so we don't have to get it again
val = foreignKeys[table][fieldName][2]
else:
# get the value from the other table and store it
#### I plan for this to be an infrequent query - unless something is broken here!
query = "SELECT " + otherTableKey + " FROM " + otherTable + " LIMIT 1"
val = queryDatabaseSingleRowCol(db, query)
foreignKeys[table][fieldName].append(val)
fieldVals += val
else:
fieldVals += getDefaultFieldVal(type)
count = count + 1
if count != len(fieldNamesToTypes):
fieldNames += ","
fieldVals += ","
# return the default field value for a given field type which will be used to prepopulate our tables
def getDefaultFieldVal(type):
if not ('insertTime' in globals()):
global insertTime
insertTime = datetime.utcnow()
# store this time in a file so that it can be retrieved by SkyReporterTest.perfoutput.py
try:
timeFileName = perfTestDir + "/dbTime.txt"
timeFile = open(timeFileName, 'w')
timeFile.write(str(insertTime))
except:
print "!!! cannot open file " + timeFileName + " for writing. Please make sure this is run where you have write permissions\n"
os.exit(1)
# many of the types are formatted with a typename, followed by a size in parentheses
##### Looking at this more closely, I suppose I could be compiling this once instead of over and over - a bit bottleneck here?
p = re.compile("(.*)\(([0-9]+).*")
size = 0
if (p.match(type)):
size = int(p.sub(r"\2", type))
type = p.sub(r"\1", type)
else:
size = 0
if (type == "tinyint"):
return str(random.randint(1, math.pow(2,7)))
elif (type == "smallint"):
return str(random.randint(1, math.pow(2,15)))
elif (type == "mediumint"):
return str(random.randint(1, math.pow(2,23)))
elif (type == "int" or type == "integer"):
return str(random.randint(1, math.pow(2,31)))
elif (type == "bigint"):
return str(random.randint(1, math.pow(2,63)))
elif (type == "float" or type == "double" or type == "doubleprecision" or type == "decimal" or type == "realdecimal" or type == "numeric"):
return str(random.random() * 100000000) # random endpoints for this random
elif (type == "date"):
insertTime = insertTime - timedelta(seconds=1)
return "'" + insertTime.strftime("%Y-%m-%d") + "'"
elif (type == "datetime"):
insertTime = insertTime - timedelta(seconds=1)
return "'" + insertTime.strftime("%Y-%m-%d %H:%M:%S") + "'"
elif (type == "timestamp"):
insertTime = insertTime - timedelta(seconds=1)
return "'" + insertTime.strftime("%Y%m%d%H%M%S") + "'"
elif (type == "time"):
insertTime = insertTime - timedelta(seconds=1)
return "'" + insertTime.strftime("%H:%M:%S") + "'"
elif (type == "year"):
insertTime = insertTime - timedelta(seconds=1)
return "'" + insertTime.strftime("%Y") + "'"
elif (type == "char" or type == "varchar" or type == "tinyblog" or type == "tinytext" or type == "blob" or type == "text" or type == "mediumblob"
or type == "mediumtext" or type == "longblob" or type == "longtext"):
if (size == 0): # not specified
return "'a'"
else:
lst = [random.choice(string.ascii_letters + string.digits) for n in xrange(size)]
strn = "".join(lst)
return strn
elif (type == "enum"):
return "NULL" # TBD if needed
elif (type == "set"):
return "NULL" # TBD if needed
else:
print "!!! Unrecognized mysql type: " + type + "\n"
os.exit(1)
파일은 ASCII 형식입니다. – vmayer
글쎄, 이것은 당신의 코드가하는 것에 상당히 의존한다! 그것은 무엇을합니까? – Cameron
프로그램이 I/O 바인딩 인 경우 C++로 전환 할 때 많은 이점을 얻지 못할 것이지만 적절한 버퍼링을 처리해야합니다. – Tibor