Commit 5e02ad1c authored by Kai Willadsen's avatar Kai Willadsen

Add multiprocessing-based inline diff comparisons

This commit introduces a simple multi-process worker model for
calculating inter-chunk differences for inline highlighting purposes.
The result is significantly better responsiveness, and an overall
performance boost for any system with multiple processors.
parent fc7f372a
### Copyright (C) 2002-2006 Stephen Kennedy <>
### Copyright (C) 2009-2010 Kai Willadsen <>
### Copyright (C) 2009-2012 Kai Willadsen <>
### This program is free software; you can redistribute it and/or modify
### it under the terms of the GNU General Public License as published by
......@@ -17,6 +17,8 @@
import codecs
import copy
import functools
import multiprocessing
import os
from gettext import gettext as _
import sys
......@@ -44,6 +46,13 @@ from meldapp import app
from util.sourceviewer import srcviewer
def matcher_worker(text1, textn):
matcher = matchers.InlineMyersSequenceMatcher(None, text1, textn)
return matcher.get_opcodes()
process_pool = multiprocessing.Pool()
class CachedSequenceMatcher(object):
"""Simple class for caching diff results, with LRU-based eviction
......@@ -55,15 +64,16 @@ class CachedSequenceMatcher(object):
def __init__(self):
self.cache = {}
def __call__(self, text1, textn):
def match(self, text1, textn, cb):
self.cache[(text1, textn)][1] = time.time()
return self.cache[(text1, textn)][0]
cb(self.cache[(text1, textn)][0])
except KeyError:
matcher = matchers.InlineMyersSequenceMatcher(None, text1, textn)
opcodes = matcher.get_opcodes()
self.cache[(text1, textn)] = [opcodes, time.time()]
return opcodes
def inline_cb(opcodes):
self.cache[(text1, textn)] = [opcodes, time.time()]
process_pool.apply_async(matcher_worker, (text1, textn),
def clean(self, size_hint):
"""Clean the cache if necessary
......@@ -1156,15 +1166,13 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
end.set_offset(offset + o[2 + 2 * i])
bufs[i].apply_tag(tags[i], start, end)
def highlight_cb(bufs, tags, starts, ends, text1, textn, clear):
matches = self._cached_match(text1, textn)
if clear:
bufs[0].remove_tag(tags[0], starts[0], ends[0])
bufs[1].remove_tag(tags[1], starts[1], ends[1])
apply_highlight(bufs, tags, starts, matches)
return False
gobject.idle_add(highlight_cb, bufs, tags, starts, ends, text1, textn, clear)
if clear:
bufs[0].remove_tag(tags[0], starts[0], ends[0])
bufs[1].remove_tag(tags[1], starts[1], ends[1])
match_cb = functools.partial(apply_highlight,
bufs, tags, starts)
matches = self._cached_match.match(text1, textn, match_cb)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment