Preload viewer conversion worker for a slight speedup on first open

This commit is contained in:
Kovid Goyal 2025-04-07 06:13:06 +05:30
parent 1a0a1a31bd
commit 32c3ea445c
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 31 additions and 16 deletions

View File

@ -2,6 +2,7 @@
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net> # License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
import atexit
import errno import errno
import json import json
import os import os
@ -12,7 +13,6 @@ from itertools import count
from calibre import walk from calibre import walk
from calibre.constants import cache_dir, iswindows from calibre.constants import cache_dir, iswindows
from calibre.ptempfile import TemporaryFile
from calibre.srv.render_book import RENDER_VERSION from calibre.srv.render_book import RENDER_VERSION
from calibre.utils.filenames import rmtree from calibre.utils.filenames import rmtree
from calibre.utils.ipc.simple_worker import start_pipe_worker from calibre.utils.ipc.simple_worker import start_pipe_worker
@ -163,32 +163,46 @@ class ConversionFailure(ValueError):
self, f'Failed to convert book: {book_path} with error:\n{worker_output}') self, f'Failed to convert book: {book_path} with error:\n{worker_output}')
preloaded_worker = None
running_workers = [] running_workers = []
def create_worker():
import subprocess
return start_pipe_worker('from calibre.srv.render_book import viewer_main; viewer_main()', stderr=subprocess.STDOUT)
def clean_running_workers(): def clean_running_workers():
global preloaded_worker
if preloaded_worker is not None:
preloaded_worker.kill()
preloaded_worker = None
for p in running_workers: for p in running_workers:
if p.poll() is None: if p.poll() is None:
p.kill() p.kill()
del running_workers[:] del running_workers[:]
def initialize_worker():
global preloaded_worker
if preloaded_worker is None:
preloaded_worker = create_worker()
atexit.register(clean_running_workers)
def do_convert(path, temp_path, key, instance): def do_convert(path, temp_path, key, instance):
global preloaded_worker
tdir = os.path.join(temp_path, instance['path']) tdir = os.path.join(temp_path, instance['path'])
p = None p = preloaded_worker or create_worker()
preloaded_worker = create_worker()
running_workers.append(p)
data = msgpack_dumps((
path, tdir, {'size': instance['file_size'], 'mtime': instance['file_mtime'], 'hash': key},
))
try: try:
with TemporaryFile('log.txt') as logpath: stdout, _ = p.communicate(data)
with open(logpath, 'w+b') as logf: if p.returncode != 0:
p = start_pipe_worker('from calibre.srv.render_book import viewer_main; viewer_main()', stdout=logf, stderr=logf) raise ConversionFailure(path, stdout.decode('utf-8', 'replace'))
running_workers.append(p)
p.stdin.write(msgpack_dumps((
path, tdir, {'size': instance['file_size'], 'mtime': instance['file_mtime'], 'hash': key},
)))
p.stdin.close()
if p.wait() != 0:
with open(logpath, 'rb') as logf:
worker_output = logf.read().decode('utf-8', 'replace')
raise ConversionFailure(path, worker_output)
finally: finally:
try: try:
running_workers.remove(p) running_workers.remove(p)

View File

@ -146,6 +146,8 @@ View an e-book.
def run_gui(app, opts, args, internal_book_data, listener=None): def run_gui(app, opts, args, internal_book_data, listener=None):
from calibre.gui2.viewer.convert_book import initialize_worker
initialize_worker()
acc = EventAccumulator(app) acc = EventAccumulator(app)
app.file_event_hook = acc app.file_event_hook = acc
app.load_builtin_fonts() app.load_builtin_fonts()

View File

@ -42,7 +42,7 @@ from calibre.gui2.viewer import get_boss, get_current_book_data, performance_mon
from calibre.gui2.viewer.annotations import AnnotationsSaveWorker, annotations_dir, parse_annotations from calibre.gui2.viewer.annotations import AnnotationsSaveWorker, annotations_dir, parse_annotations
from calibre.gui2.viewer.bookmarks import BookmarkManager from calibre.gui2.viewer.bookmarks import BookmarkManager
from calibre.gui2.viewer.config import get_session_pref, load_reading_rates, save_reading_rates, vprefs from calibre.gui2.viewer.config import get_session_pref, load_reading_rates, save_reading_rates, vprefs
from calibre.gui2.viewer.convert_book import clean_running_workers, prepare_book from calibre.gui2.viewer.convert_book import prepare_book
from calibre.gui2.viewer.highlights import HighlightsPanel from calibre.gui2.viewer.highlights import HighlightsPanel
from calibre.gui2.viewer.integration import get_book_library_details, load_annotations_map_from_library from calibre.gui2.viewer.integration import get_book_library_details, load_annotations_map_from_library
from calibre.gui2.viewer.lookup import Lookup from calibre.gui2.viewer.lookup import Lookup
@ -837,7 +837,6 @@ class EbookViewer(MainWindow):
except Exception: except Exception:
import traceback import traceback
traceback.print_exc() traceback.print_exc()
clean_running_workers()
self.shutdown_done = True self.shutdown_done = True
return MainWindow.closeEvent(self, ev) return MainWindow.closeEvent(self, ev)
# }}} # }}}