bpo-43785: Improve BZ2File performance by removing RLock (GH-25299) · python/cpython@cc2ffcd

GitHub

@@ -13,7 +13,6 @@

1313importio

1414importos

1515import_compression

16-fromthreadingimportRLock

17161817from_bz2importBZ2Compressor, BZ2Decompressor

1918@@ -53,9 +52,6 @@ def __init__(self, filename, mode="r", *, compresslevel=9):

5352 If mode is 'r', the input file may be the concatenation of

5453 multiple compressed streams.

5554 """

56-# This lock must be recursive, so that BufferedIOBase's

57-# writelines() does not deadlock.

58-self._lock=RLock()

5955self._fp=None

6056self._closefp=False

6157self._mode=_MODE_CLOSED

@@ -104,24 +100,23 @@ def close(self):

104100 May be called more than once without error. Once the file is

105101 closed, any other operation on it will raise a ValueError.

106102 """

107-withself._lock:

108-ifself._mode==_MODE_CLOSED:

109-return

103+ifself._mode==_MODE_CLOSED:

104+return

105+try:

106+ifself._mode==_MODE_READ:

107+self._buffer.close()

108+elifself._mode==_MODE_WRITE:

109+self._fp.write(self._compressor.flush())

110+self._compressor=None

111+finally:

110112try:

111-ifself._mode==_MODE_READ:

112-self._buffer.close()

113-elifself._mode==_MODE_WRITE:

114-self._fp.write(self._compressor.flush())

115-self._compressor=None

113+ifself._closefp:

114+self._fp.close()

116115finally:

117-try:

118-ifself._closefp:

119-self._fp.close()

120-finally:

121-self._fp=None

122-self._closefp=False

123-self._mode=_MODE_CLOSED

124-self._buffer=None

116+self._fp=None

117+self._closefp=False

118+self._mode=_MODE_CLOSED

119+self._buffer=None

125120126121@property

127122defclosed(self):

@@ -153,22 +148,20 @@ def peek(self, n=0):

153148 Always returns at least one byte of data, unless at EOF.

154149 The exact number of bytes returned is unspecified.

155150 """

156-withself._lock:

157-self._check_can_read()

158-# Relies on the undocumented fact that BufferedReader.peek()

159-# always returns at least one byte (except at EOF), independent

160-# of the value of n

161-returnself._buffer.peek(n)

151+self._check_can_read()

152+# Relies on the undocumented fact that BufferedReader.peek()

153+# always returns at least one byte (except at EOF), independent

154+# of the value of n

155+returnself._buffer.peek(n)

162156163157defread(self, size=-1):

164158"""Read up to size uncompressed bytes from the file.

165159166160 If size is negative or omitted, read until EOF is reached.

167161 Returns b'' if the file is already at EOF.

168162 """

169-withself._lock:

170-self._check_can_read()

171-returnself._buffer.read(size)

163+self._check_can_read()

164+returnself._buffer.read(size)

172165173166defread1(self, size=-1):

174167"""Read up to size uncompressed bytes, while trying to avoid

@@ -177,20 +170,18 @@ def read1(self, size=-1):

177170178171 Returns b'' if the file is at EOF.

179172 """

180-withself._lock:

181-self._check_can_read()

182-ifsize<0:

183-size=io.DEFAULT_BUFFER_SIZE

184-returnself._buffer.read1(size)

173+self._check_can_read()

174+ifsize<0:

175+size=io.DEFAULT_BUFFER_SIZE

176+returnself._buffer.read1(size)

185177186178defreadinto(self, b):

187179"""Read bytes into b.

188180189181 Returns the number of bytes read (0 for EOF).

190182 """

191-withself._lock:

192-self._check_can_read()

193-returnself._buffer.readinto(b)

183+self._check_can_read()

184+returnself._buffer.readinto(b)

194185195186defreadline(self, size=-1):

196187"""Read a line of uncompressed bytes from the file.

@@ -203,9 +194,8 @@ def readline(self, size=-1):

203194ifnothasattr(size, "__index__"):

204195raiseTypeError("Integer argument expected")

205196size=size.__index__()

206-withself._lock:

207-self._check_can_read()

208-returnself._buffer.readline(size)

197+self._check_can_read()

198+returnself._buffer.readline(size)

209199210200defreadlines(self, size=-1):

211201"""Read a list of lines of uncompressed bytes from the file.

@@ -218,9 +208,8 @@ def readlines(self, size=-1):

218208ifnothasattr(size, "__index__"):

219209raiseTypeError("Integer argument expected")

220210size=size.__index__()

221-withself._lock:

222-self._check_can_read()

223-returnself._buffer.readlines(size)

211+self._check_can_read()

212+returnself._buffer.readlines(size)

224213225214defwrite(self, data):

226215"""Write a byte string to the file.

@@ -229,12 +218,11 @@ def write(self, data):

229218 always len(data). Note that due to buffering, the file on disk

230219 may not reflect the data written until close() is called.

231220 """

232-withself._lock:

233-self._check_can_write()

234-compressed=self._compressor.compress(data)

235-self._fp.write(compressed)

236-self._pos+=len(data)

237-returnlen(data)

221+self._check_can_write()

222+compressed=self._compressor.compress(data)

223+self._fp.write(compressed)

224+self._pos+=len(data)

225+returnlen(data)

238226239227defwritelines(self, seq):

240228"""Write a sequence of byte strings to the file.

@@ -244,8 +232,7 @@ def writelines(self, seq):

244232245233 Line separators are not added between the written byte strings.

246234 """

247-withself._lock:

248-return_compression.BaseStream.writelines(self, seq)

235+return_compression.BaseStream.writelines(self, seq)

249236250237defseek(self, offset, whence=io.SEEK_SET):

251238"""Change the file position.

@@ -262,17 +249,15 @@ def seek(self, offset, whence=io.SEEK_SET):

262249 Note that seeking is emulated, so depending on the parameters,

263250 this operation may be extremely slow.

264251 """

265-withself._lock:

266-self._check_can_seek()

267-returnself._buffer.seek(offset, whence)

252+self._check_can_seek()

253+returnself._buffer.seek(offset, whence)

268254269255deftell(self):

270256"""Return the current file position."""

271-withself._lock:

272-self._check_not_closed()

273-ifself._mode==_MODE_READ:

274-returnself._buffer.tell()

275-returnself._pos

257+self._check_not_closed()

258+ifself._mode==_MODE_READ:

259+returnself._buffer.tell()

260+returnself._pos

276261277262278263defopen(filename, mode="rb", compresslevel=9,