Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit fe1e48a

Browse files
committed
Merge pull request #798 from jdh2358/class-font-cache
use class level rather than instance level caching of fontd
2 parents 1d55641 + a00e510 commit fe1e48a

File tree

1 file changed

+32
-8
lines changed

1 file changed

+32
-8
lines changed

lib/matplotlib/backends/backend_agg.py

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
* integrate screen dpi w/ ppi and text
2222
"""
2323
from __future__ import division
24-
24+
import threading
2525
import numpy as np
2626

2727
from matplotlib import verbose, rcParams
@@ -46,11 +46,24 @@ class RendererAgg(RendererBase):
4646
context instance that controls the colors/styles
4747
"""
4848
debug=1
49+
50+
# we want to cache the fonts at the class level so that when
51+
# multiple figures are created we can reuse them. This helps with
52+
# a bug on windows where the creation of too many figures leads to
53+
# too many open file handles. However, storing them at the class
54+
# level is not thread safe. The solution here is to let the
55+
# FigureCanvas acquire a lock on the fontd at the start of the
56+
# draw, and release it when it is done. This allows multiple
57+
# renderers to share the cached fonts, but only one figure can
58+
# draw at at time and so the font cache is used by only one
59+
# renderer at a time
60+
61+
lock = threading.Lock()
62+
_fontd = maxdict(50)
4963
def __init__(self, width, height, dpi):
5064
if __debug__: verbose.report('RendererAgg.__init__', 'debug-annoying')
5165
RendererBase.__init__(self)
5266
self.texd = maxdict(50) # a cache of tex image rasters
53-
self._fontd = maxdict(50)
5467

5568
self.dpi = dpi
5669
self.width = width
@@ -69,6 +82,7 @@ def __init__(self, width, height, dpi):
6982
if __debug__: verbose.report('RendererAgg.__init__ done',
7083
'debug-annoying')
7184

85+
7286
def _get_hinting_flag(self):
7387
if rcParams['text.hinting']:
7488
return LOAD_FORCE_AUTOHINT
@@ -82,7 +96,7 @@ def draw_markers(self, *kl, **kw):
8296

8397
def draw_path_collection(self, *kl, **kw):
8498
return self._renderer.draw_path_collection(*kl, **kw)
85-
99+
86100
def _update_methods(self):
87101
#self.draw_path = self._renderer.draw_path # see below
88102
#self.draw_markers = self._renderer.draw_markers
@@ -215,15 +229,16 @@ def _get_agg_font(self, prop):
215229
'debug-annoying')
216230

217231
key = hash(prop)
218-
font = self._fontd.get(key)
232+
font = RendererAgg._fontd.get(key)
219233

220234
if font is None:
221235
fname = findfont(prop)
222-
font = self._fontd.get(fname)
236+
font = RendererAgg._fontd.get(fname)
223237
if font is None:
224238
font = FT2Font(str(fname))
225-
self._fontd[fname] = font
226-
self._fontd[key] = font
239+
RendererAgg._fontd[fname] = font
240+
241+
RendererAgg._fontd[key] = font
227242

228243
font.clear()
229244
size = prop.get_size_in_points()
@@ -358,6 +373,7 @@ def post_processing(image, dpi):
358373
image)
359374

360375

376+
361377
def new_figure_manager(num, *args, **kwargs):
362378
"""
363379
Create a new figure manager instance
@@ -398,7 +414,15 @@ def draw(self):
398414
if __debug__: verbose.report('FigureCanvasAgg.draw', 'debug-annoying')
399415

400416
self.renderer = self.get_renderer()
401-
self.figure.draw(self.renderer)
417+
# acquire a lock on the shared font cache
418+
RendererAgg.lock.acquire()
419+
420+
try:
421+
self.figure.draw(self.renderer)
422+
finally:
423+
RendererAgg.lock.release()
424+
425+
402426

403427
def get_renderer(self):
404428
l, b, w, h = self.figure.bbox.bounds

0 commit comments

Comments
 (0)