python多线程处理文件_PYTHON多线程处理文件

一个几十G的文件想用Python多线程读取提高处理效率,得到的结果总是不如预期。在毛帅的提醒下才发现一个进程启动的线程将共享文件句柄,A线程对文件的操作(即使是读)也将影响到B线程。如图,图片来自毛帅:

194342_5R8k_551773.jpg

测试代码如下:

# -*- coding: UTF-8 -*-

def threadFunc1(demo, threadnum, startlinenum, deallinenum):

# 行数计数器

line = 0

# skip若干行

while line < startlinenum:

lineStr = demo.readline()

line += 1

# deal指定行数

while line < deallinenum:

lineStr = demo.readline()

line += 1

print "Thread-%s:%s" % (threadnum, lineStr)

def threadFunc2(demo, threadnum, startlinenum, deallinenum):

linenum = 1

for line in demo:

if linenum >= startlinenum and linenum < (startlinenum+deallinenum):

print "Thread-%s:%s" % (threadnum, line)

elif (linenum >= (startlinenum+deallinenum)):

break;

linenum = linenum+1

import threading

if __name__ == "__main__":

# 初始化demo文件

fileLoc = 'demo.txt'

demo = open(fileLoc,'w')

for i in range(100000):

demo.write("Line:"+str(i)+'\n')

demo.close()

# 预读文件总行数

demo = open(fileLoc,'r')

filetotalnum = 0

for line in demo:

filetotalnum = filetotalnum + 1

demo.close()

# 设定线程数

TOTAL_THREAD = 6

# 在主进程总打开文件,将文件句柄传至线程启动的函数中

demo = open(fileLoc,'r')

for threadnum in range(TOTAL_THREAD):

# 每个线程处理的行数

deallinenum = filetotalnum / (TOTAL_THREAD-1)

# 最后一个线程处理剩余部分

leftnum = filetotalnum % (TOTAL_THREAD-1)

if(threadnum != (TOTAL_THREAD-1)):

# 实例化线程

t = threading.Thread(target=threadFunc2,args=(demo, threadnum, threadnum*deallinenum, threadnum*deallinenum+deallinenum))

# 启动

t.start()

# 等待线程结束后主进程退出

t.join()

else :

t = threading.Thread(target=threadFunc2,args=(demo, threadnum, threadnum*deallinenum, threadnum*deallinenum+leftnum))

t.start()

t.join()

threadFunc2函数中利用句柄参数读取文件,但结果是有些线程有正常输出,其它一些线程则无输出。目测原因是线程切换的随机性影响了本来应正常进行读取的线程(例如一些线程正好定位到属于其处理范围的行时发生线程切换,而其它线程获得时间片后在这个位置基础上继续处理)。

threadFunc1使用readLine进行读取,但本质同threadFunc2一样。

如果传给threadFuncx的并不是在主线程中打开的文件句柄而是一个文件路径,并在threadFuncx内部打开文件,结果表现为各个线程都有输出,但是输出的内容并非分配给其的文件片段的内容,有干涉。

细节上未进行深入研究,总之不加锁的情况下,python启动多线程读取文件会得到非预期结果。

至于最后的解决方案,是利用awk对文件进行“模数切割”,Mod的不同余数分别对应一个处理线程。

targetFile=xxx

threadNum=5 # 设定五个线程

for((i=0; i

do

awk 'NR%n==t {print $0}' n=$threadNum t=$i $targetFile | python doTask.py &

done

如果文章对你有用,请在收藏之余“顶/赞”一下以示鼓励吧 (/ω\)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值