Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changed BackgroundWorkers to async await #728

Draft
wants to merge 10 commits into
base: master
Choose a base branch
from
8 changes: 8 additions & 0 deletions Glyssen/MainForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,14 @@ private void SetProject(Project project)
}

private void FinishSetProjectIfReady(object sender, EventArgs e)
{
if (InvokeRequired)
Invoke(new Action(FinishSetProjectIfReady));
else
FinishSetProjectIfReady();
}

private void FinishSetProjectIfReady()
{
if (m_project != null && (m_project.ProjectState & ProjectState.ReadyForUserInteraction) > 0)
FinishSetProject();
Expand Down
134 changes: 44 additions & 90 deletions GlyssenEngine/Project.cs
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ public void SetQuoteSystem(QuoteSystemStatus status, QuoteSystem system)
if (IsQuoteSystemReadyForParse && ProjectState == ProjectState.NeedsQuoteSystemConfirmation)
{
m_quoteSystem = system;
DoQuoteParse();
DoQuoteParseAsync();
}
else if ((quoteSystemChanged && !quoteSystemBeingSetForFirstTime) ||
(QuoteSystemStatus == QuoteSystemStatus.Reviewed &&
Expand Down Expand Up @@ -1344,7 +1344,7 @@ private void InitializeLoadedProject()
m_usxPercentComplete = 100;
if (QuoteSystem == null)
{
GuessAtQuoteSystem();
GuessAtQuoteSystemAsync();
UpdateControlFileVersion();
return;
}
Expand Down Expand Up @@ -1463,55 +1463,38 @@ private void ParseAndSetBooks(IEnumerable<UsxDocument> books, IStylesheet styles
ParseAndIncludeBooks(books, stylesheet);
}

private void ParseAndIncludeBooks(IEnumerable<UsxDocument> books, IStylesheet stylesheet, Action<BookScript> postParseAction = null)
private async Task ParseAndIncludeBooks(IEnumerable<UsxDocument> books, IStylesheet stylesheet, Action<BookScript> postParseAction = null)
{
if (Versification == null)
throw new NullReferenceException("What!!!");
ProjectState = ProjectState.Initial | (ProjectState & ProjectState.WritingSystemRecoveryInProcess);
var usxWorker = new BackgroundWorker {WorkerReportsProgress = true};
usxWorker.DoWork += UsxWorker_DoWork;
usxWorker.RunWorkerCompleted += UsxWorker_RunWorkerCompleted;
usxWorker.ProgressChanged += UsxWorker_ProgressChanged;

object[] parameters = {books, stylesheet, postParseAction};
usxWorker.RunWorkerAsync(parameters);
await Task.Run(() => {UsxParse(books, stylesheet, postParseAction);});
}

private void UsxWorker_DoWork(object sender, DoWorkEventArgs e)
private void UsxParse(IEnumerable<UsxDocument> books, IStylesheet stylesheet, Action<BookScript> postParseAction = null)
{
var parameters = (object[])e.Argument;
var books = (IEnumerable<UsxDocument>)parameters[0];
var stylesheet = (IStylesheet)parameters[1];
var postParseAction = parameters.Length > 2 ? (Action<BookScript>)parameters[2] : null;

var backgroundWorker = (BackgroundWorker)sender;

var parsedBooks = UsxParser.ParseBooks(books, stylesheet, i => backgroundWorker.ReportProgress(i));
var parsedBooks = UsxParser.ParseBooks(books, stylesheet, i =>
{
m_usxPercentComplete = i;
var pe = new ProgressChangedEventArgs(PercentInitialized, null);
OnReport(pe);
});

if (postParseAction != null)
{
foreach (var book in parsedBooks)
postParseAction(book);
}
e.Result = parsedBooks;
}

private void UsxWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
throw e.Error;

var bookScripts = (List<BookScript>)e.Result;

foreach (var bookScript in bookScripts)
foreach (var bookScript in parsedBooks)
{
// This code is an attempt to figure out how we are getting null reference exceptions when using the objects in the list (See PG-275 & PG-287)
if (bookScript?.BookId == null)
{
var nonNullBookScripts = bookScripts.Where(b => b != null).Select(b => b.BookId);
var nonNullBookScripts = parsedBooks.Where(b => b != null).Select(b => b.BookId);
var nonNullBookScriptsStr = Join(";", nonNullBookScripts);
var initialMessage = bookScript == null ? "BookScript is null." : "BookScript has null BookId.";
throw new ApplicationException($"{initialMessage} Number of BookScripts: {bookScripts.Count}. " +
throw new ApplicationException($"{initialMessage} Number of BookScripts: {parsedBooks.Count}. " +
$"BookScripts which are NOT null: {nonNullBookScriptsStr}");
}

Expand All @@ -1520,12 +1503,12 @@ private void UsxWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEvent

if (m_books.Any())
{
foreach (var book in bookScripts)
foreach (var book in parsedBooks)
IncludeExistingBook(book);
}
else
{
m_books.AddRange(bookScripts);
m_books.AddRange(parsedBooks);
m_projectMetadata.ParserVersion = kParserVersion;
if (m_books.All(b => IsNullOrEmpty(b.PageHeader)))
ChapterAnnouncementStyle = ChapterAnnouncement.ChapterLabel;
Expand All @@ -1535,79 +1518,57 @@ private void UsxWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEvent
}

if (QuoteSystem == null)
GuessAtQuoteSystem();
GuessAtQuoteSystemAsync();
else if (IsQuoteSystemReadyForParse)
DoQuoteParse(bookScripts.Select(b => b.BookId));
DoQuoteParseAsync(parsedBooks.Select(b => b.BookId));
}

private void UsxWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
m_usxPercentComplete = e.ProgressPercentage;
var pe = new ProgressChangedEventArgs(PercentInitialized, null);
OnReport(pe);
}

private void GuessAtQuoteSystem()
private async Task GuessAtQuoteSystemAsync()
{
ProjectState = ProjectState.UsxComplete | (ProjectState & ProjectState.WritingSystemRecoveryInProcess);
var guessWorker = new BackgroundWorker {WorkerReportsProgress = true};
guessWorker.DoWork += GuessWorker_DoWork;
guessWorker.RunWorkerCompleted += GuessWorker_RunWorkerCompleted;
guessWorker.ProgressChanged += GuessWorker_ProgressChanged;
guessWorker.RunWorkerAsync();
await Task.Run(GuessAtQuoteSystem);
}

private void GuessWorker_DoWork(object sender, DoWorkEventArgs e)
{
e.Result = QuoteSystemGuesser.Guess(ControlCharacterVerseData.Singleton, m_books, Versification, out _,
sender as BackgroundWorker);
}

private void GuessWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
private void GuessAtQuoteSystem()
{
if (e.Error != null)
throw e.Error;

SetQuoteSystem(QuoteSystemStatus.Guessed, (QuoteSystem)e.Result);
var quoteSystem = QuoteSystemGuesser.Guess(ControlCharacterVerseData.Singleton, m_books, Versification, out _,
i =>
{
m_guessPercentComplete = i;
var pe = new ProgressChangedEventArgs(PercentInitialized, null);
OnReport(pe);
});

SetQuoteSystem(QuoteSystemStatus.Guessed, quoteSystem);
Save();
}

private void GuessWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
m_guessPercentComplete = e.ProgressPercentage;
var pe = new ProgressChangedEventArgs(PercentInitialized, null);
OnReport(pe);
}

private void DoQuoteParse(IEnumerable<string> booksToParse = null)
private async Task DoQuoteParseAsync(IEnumerable<string> booksToParse = null)
{
m_projectMetadata.ParserVersion = kParserVersion;
ProjectState = ProjectState.Parsing;
var quoteWorker = new BackgroundWorker {WorkerReportsProgress = true};
quoteWorker.DoWork += QuoteWorker_DoWork;
quoteWorker.RunWorkerCompleted += QuoteWorker_RunWorkerCompleted;
quoteWorker.ProgressChanged += QuoteWorker_ProgressChanged;
object[] parameters = {booksToParse};
quoteWorker.RunWorkerAsync(parameters);
}

private void QuoteWorker_DoWork(object sender, DoWorkEventArgs e)
{
var bookIds = (IEnumerable<string>)((object[])e.Argument)[0];
QuoteParser.ParseProject(this, sender as BackgroundWorker, bookIds);
await Task.Run(() => { DoQuoteParse(booksToParse);});
}

private void QuoteWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
private void DoQuoteParse(IEnumerable<string> bookIds)
{
if (e.Error != null)
try
{
QuoteParser.ParseProject(this, i =>
{
m_quotePercentComplete = i;
var pe = new ProgressChangedEventArgs(PercentInitialized, null);
OnReport(pe);
}, bookIds);
}
catch (Exception e)
{
#if DEBUG
Exception innerException;
if ((innerException = e.Error?.InnerException) != null)
if ((innerException = e.InnerException) != null)
Debug.WriteLine(innerException.Message + innerException.StackTrace);
#endif
throw e.Error;
throw;
}

ProjectState = ProjectState.QuoteParseComplete;
Expand All @@ -1628,13 +1589,6 @@ private void QuoteWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEve
QuoteParseCompleted?.Invoke(this, new EventArgs());
}

private void QuoteWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
m_quotePercentComplete = e.ProgressPercentage;
var pe = new ProgressChangedEventArgs(PercentInitialized, null);
OnReport(pe);
}

public int MaxProjectNameLength => Writer.GetMaxProjectNameLength(this);

public BookScript LoadExistingBookIfPossible(string bookId)
Expand Down
7 changes: 3 additions & 4 deletions GlyssenEngine/Quote/QuoteParser.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
Expand All @@ -21,7 +20,7 @@ namespace GlyssenEngine.Quote
{
public class QuoteParser
{
public static void ParseProject(Project project, BackgroundWorker projectWorker, IEnumerable<string> bookIdsToParse)
public static void ParseProject(Project project, Action<int> reportProgress, IEnumerable<string> bookIdsToParse)
{
var cvInfo = new ParserCharacterRepository(new CombinedCharacterVerseData(project), project.ReferenceText);

Expand All @@ -43,10 +42,10 @@ public static void ParseProject(Project project, BackgroundWorker projectWorker,
{
book.Blocks = new QuoteParser(cvInfo, book.BookId, blocksInBook[book], project.Versification).Parse().ToList();
completedProjectBlocks += numBlocksPerBook[book.BookId];
projectWorker.ReportProgress(MathUtilities.Percent(completedProjectBlocks, allProjectBlocks, 99));
reportProgress(MathUtilities.Percent(completedProjectBlocks, allProjectBlocks, 99));
});

projectWorker.ReportProgress(100);
reportProgress(100);
}

public static void SetQuoteSystem(QuoteSystem quoteSystem)
Expand Down
22 changes: 7 additions & 15 deletions GlyssenEngine/Quote/QuoteSystemGuesser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using Glyssen.Shared;
Expand Down Expand Up @@ -37,13 +36,13 @@ private static void IncrementScore(Dictionary<QuoteSystem, int> scores, QuoteSys
bestScore = scores[quoteSystem];
}

public static QuoteSystem Guess<T>(ICharacterVerseInfo cvInfo, List<T> bookList, ScrVers versification, out bool certain, BackgroundWorker worker = null) where T : IScrBook
public static QuoteSystem Guess<T>(ICharacterVerseInfo cvInfo, List<T> bookList, ScrVers versification, out bool certain, Action<int> reportProgress = null) where T : IScrBook
{
certain = false;
var bookCount = bookList.Count;
if (bookCount == 0)
{
ReportProgressComplete(worker);
reportProgress?.Invoke(100);
return QuoteSystem.Default;
}
var scores = QuoteSystem.UniquelyGuessableSystems.ToDictionary(s => s, s => 0);
Expand Down Expand Up @@ -73,8 +72,7 @@ public static QuoteSystem Guess<T>(ICharacterVerseInfo cvInfo, List<T> bookList,
var bookNum = bookTuple.Item1;
var book = bookTuple.Item2;

if (worker != null)
worker.ReportProgress(MathUtilities.Percent(++booksProcessed, bookCount));
reportProgress?.Invoke(MathUtilities.Percent(++booksProcessed, bookCount));

int versesAnalyzedForCurrentBook = 0;
int prevQuoteChapter = -1;
Expand Down Expand Up @@ -209,7 +207,7 @@ public static QuoteSystem Guess<T>(ICharacterVerseInfo cvInfo, List<T> bookList,
if (competitors.Count == 1)
{
certain = true;
ReportProgressComplete(worker);
reportProgress?.Invoke(100);
return competitors[0];
}

Expand Down Expand Up @@ -297,7 +295,7 @@ public static QuoteSystem Guess<T>(ICharacterVerseInfo cvInfo, List<T> bookList,

if (competitors.Any())
{
ReportProgressComplete(worker);
reportProgress?.Invoke(100);

if (competitors.Count == 1)
return competitors[0];
Expand Down Expand Up @@ -327,15 +325,15 @@ public static QuoteSystem Guess<T>(ICharacterVerseInfo cvInfo, List<T> bookList,
#if SHOWTESTINFO
Debug.WriteLine("Time-out guessing quote system.");
#endif
ReportProgressComplete(worker);
reportProgress?.Invoke(100);
return BestGuess(viableSystems, scores, bestScore, foundEndQuote);
}

prevQuoteChapter = quote.Chapter;
prevQuoteVerse = quote.Verse;
}
}
ReportProgressComplete(worker);
reportProgress?.Invoke(100);
return BestGuess(viableSystems, scores, bestScore, foundEndQuote);
}

Expand Down Expand Up @@ -427,11 +425,5 @@ private static QuoteSystem BestGuess(IEnumerable<QuoteSystem> viableSystems, Dic
// newSystem.AllLevels.Add(QuoteUtils.GenerateLevel3(newSystem, true));
// return newSystem;
//}

private static void ReportProgressComplete(BackgroundWorker worker)
{
if (worker != null)
worker.ReportProgress(100);
}
}
}