Skip to content

Commit 4d982af

Browse files
committed
Improve multithreading/async operations; improve design
1 parent e91bbd6 commit 4d982af

File tree

4 files changed

+104
-102
lines changed

4 files changed

+104
-102
lines changed

SmartImage.Lib/SearchClient.cs

Lines changed: 84 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ public sealed class SearchClient
2828
{
2929
public SearchClient(SearchConfig config)
3030
{
31-
Config = config;
31+
Config = config;
3232

3333
Results = new List<SearchResult>();
3434
FilteredResults = new List<SearchResult>();
35-
35+
DirectResults = new List<ImageResult>();
3636
Reload();
3737
}
3838

@@ -55,8 +55,8 @@ public SearchClient(SearchConfig config)
5555
/// Contains search results
5656
/// </summary>
5757
public List<SearchResult> Results { get; }
58-
5958

59+
public List<ImageResult> DirectResults { get; }
6060

6161
/// <summary>
6262
/// Contains filtered search results
@@ -87,12 +87,20 @@ public void Reload()
8787
public void Reset()
8888
{
8989
Results.Clear();
90+
DirectResults.Clear();
9091
FilteredResults.Clear();
9192
IsComplete = false;
9293
Reload();
9394
}
9495

95-
#region Primary operations
96+
/*
97+
* TODO
98+
*
99+
* Queue a thread to run in the background upon each result completion
100+
* in which the thread scans for direct images, instead of doing the scanning post hoc
101+
*/
102+
103+
#region
96104

97105
/// <summary>
98106
/// Performs an image search asynchronously.
@@ -106,7 +114,7 @@ public async Task RunSearchAsync()
106114
var tasks = new List<Task<SearchResult>>(Engines.Select(e =>
107115
{
108116
var task = e.GetResultAsync(Config.Query);
109-
117+
110118
return task;
111119
}));
112120

@@ -151,6 +159,8 @@ public async Task RunSearchAsync()
151159
isFiltered = null;
152160
}
153161

162+
ThreadPool.QueueUserWorkItem((c) => FindDirectResults(c, value));
163+
154164
// Call event
155165
ResultCompleted?.Invoke(null, new ResultCompletedEventArgs(value)
156166
{
@@ -163,34 +173,78 @@ public async Task RunSearchAsync()
163173

164174
Trace.WriteLine($"{nameof(SearchClient)}: Search complete", C_SUCCESS);
165175

176+
166177
var args = new SearchCompletedEventArgs
167178
{
168-
Results = Results,
169-
Detailed = new Lazy<ImageResult>(() => GetDetailedImageResults().FirstOrDefault()),
170-
Direct = new Lazy<ImageResult[]>(() =>
179+
Results = Results,
180+
FirstDetailed = RefineFilter(DetailPredicate).FirstOrDefault(),
181+
/*Direct = new Lazy<ImageResult[]>(() =>
171182
{
172183
Debug.WriteLine($"{nameof(SearchClient)}: Finding direct results", C_DEBUG);
173184
ImageResult[] direct = GetDirectImageResults();
174185
175186
return direct;
176187
}),
177-
FirstDirect = new Lazy<ImageResult>(GetDirectImageResult)
188+
FirstDirect = new Lazy<ImageResult>(GetDirectImageResult)*/
189+
Direct = DirectResults,
190+
FirstDirect = DirectResults.FirstOrDefault()
178191
};
179192

180193
SearchCompleted?.Invoke(null, args);
194+
195+
181196
}
182197

198+
private void FindDirectResults(object state, SearchResult value, int count = 5, int i = 10)
199+
{
200+
var u = value.OtherResults.Union(new[] { value.PrimaryResult }).ToList();
201+
var u2 = RefineFilter(u, DirectFilterPredicate).ToList();
183202

184-
/*
185-
* TODO
186-
*
187-
* Queue a thread to run in the background upon each result completion
188-
* in which the thread scans for direct images, instead of doing the scanning post hoc
189-
*/
203+
Debug.WriteLine($"*{nameof(SearchClient)}: Found {u2.Count} best results", C_DEBUG);
190204

191-
#endregion
205+
var query = u2.Where(x => x.CheckDirect(DirectImageCriterion.Regex))
206+
.Take(i)
207+
.AsParallel();
208+
209+
List<ImageResult> images = query.Where(x => x.CheckDirect(DirectImageCriterion.Binary))
210+
.Take(count)
211+
.ToList();
212+
213+
if (images.Any()) {
214+
Debug.WriteLine($"*{nameof(SearchClient)}: Found {images.Count} direct results", C_DEBUG);
215+
DirectResults.AddRange(images);
192216

193-
#region Secondary operations
217+
DirectFound?.Invoke(null, new DirectFoundEventArgs()
218+
{
219+
Direct = images,
220+
});
221+
}
222+
}
223+
224+
225+
public static IEnumerable<ImageResult> RefineFilter(List<ImageResult> results,
226+
Predicate<SearchResult> predicate)
227+
{
228+
var query = results.AsParallel()
229+
.OrderByDescending(r => r.Similarity)
230+
.ThenByDescending(r => r.PixelResolution)
231+
.ThenByDescending(r => r.DetailScore);
232+
233+
return query;
234+
}
235+
236+
public IEnumerable<ImageResult> RefineFilter(Predicate<SearchResult> predicate)
237+
{
238+
var query = Results.Where(r => predicate(r))
239+
.SelectMany(r =>
240+
{
241+
List<ImageResult> otherResults = r.OtherResults;
242+
otherResults.Insert(0, r.PrimaryResult);
243+
return otherResults;
244+
}).ToList();
245+
246+
return RefineFilter(query, predicate);
247+
}
194248

195249
/// <summary>
196250
/// Refines search results by searching with the most-detailed result (<see cref="GetDirectImageResult" />).
@@ -203,7 +257,7 @@ public async Task RefineSearchAsync()
203257

204258
Debug.WriteLine($"{nameof(SearchClient)}: Finding best result", C_DEBUG);
205259

206-
var directResult = GetDirectImageResult();
260+
var directResult = DirectResults.FirstOrDefault();
207261

208262
if (directResult == null) {
209263
throw new SmartImageException("Could not find best result");
@@ -237,67 +291,6 @@ public List<SearchResult> MaximizeResults<T>(Func<SearchResult, T> property)
237291
return res;
238292
}
239293

240-
[CanBeNull]
241-
public ImageResult GetDirectImageResult() => GetDirectImageResults(1)?.FirstOrDefault();
242-
243-
public ImageResult[] GetDirectImageResults(int count = 5)
244-
{
245-
var imageResults = RefineFilter(DirectFilterPredicate).ToList();
246-
247-
Debug.WriteLine($"{nameof(SearchClient)}: Found {imageResults.Count} best results", C_DEBUG);
248-
249-
const int i = 10;
250-
251-
var query = imageResults.Where(x => x.CheckDirect(DirectImageCriterion.Regex))
252-
.Take(i)
253-
.AsParallel();
254-
255-
List<ImageResult> images;
256-
257-
if (count == 1)
258-
{
259-
images = new List<ImageResult>
260-
{
261-
query.FirstOrDefault(x => x.CheckDirect(DirectImageCriterion.Binary))
262-
};
263-
264-
}
265-
else
266-
{
267-
images = query.Where(x => x.CheckDirect(DirectImageCriterion.Binary))
268-
.Take(count)
269-
// .OrderByDescending(r => r.Similarity)
270-
.ToList();
271-
}
272-
273-
Debug.WriteLine($"{nameof(SearchClient)}: Found {images.Count} direct results", C_DEBUG);
274-
275-
return images.ToArray();
276-
}
277-
278-
/// <summary>
279-
/// Selects the most detailed results.
280-
/// </summary>
281-
/// <returns>The <see cref="ImageResult" />s of the best <see cref="Results" /></returns>
282-
public ImageResult[] GetDetailedImageResults() => RefineFilter(DetailPredicate).ToArray();
283-
284-
public IEnumerable<ImageResult> RefineFilter(Predicate<SearchResult> predicate)
285-
{
286-
var query = Results.Where(r => predicate(r))
287-
.SelectMany(r =>
288-
{
289-
List<ImageResult> otherResults = r.OtherResults;
290-
otherResults.Insert(0, r.PrimaryResult);
291-
return otherResults;
292-
})
293-
.AsParallel()
294-
.OrderByDescending(r => r.Similarity)
295-
.ThenByDescending(r => r.PixelResolution)
296-
.ThenByDescending(r => r.DetailScore);
297-
298-
return query;
299-
}
300-
301294
#endregion
302295

303296
public static BaseUploadEngine[] GetAllUploadEngines()
@@ -326,29 +319,35 @@ public static BaseSearchEngine[] GetAllSearchEngines()
326319
/// </summary>
327320
public event EventHandler<SearchCompletedEventArgs> SearchCompleted;
328321

322+
public event EventHandler<DirectFoundEventArgs> DirectFound;
323+
329324
private static readonly Predicate<SearchResult> DetailPredicate = r => r.IsNonPrimitive;
330325

331326
private static readonly SmartImageException SearchException = new("Search must be completed");
332327

333328
private static readonly Predicate<SearchResult> DirectFilterPredicate = r => DetailPredicate(r)
334-
&& r.Engine.SearchType.HasFlag(EngineSearchType.Image);
329+
&& r.Engine.SearchType.HasFlag(EngineSearchType.Image);
330+
}
331+
332+
public sealed class DirectFoundEventArgs : EventArgs
333+
{
334+
public List<ImageResult> Direct { get; init; }
335335
}
336336

337337
public sealed class SearchCompletedEventArgs : EventArgs
338338
{
339339
public List<SearchResult> Results { get; init; }
340340

341341
[CanBeNull]
342-
public Lazy<ImageResult[]> Direct { get; internal set; }
342+
public List<ImageResult> Direct { get; internal set; }
343343

344344
[CanBeNull]
345-
public Lazy<ImageResult> FirstDirect { get; internal set; }
345+
public ImageResult FirstDirect { get; internal set; }
346346

347347

348348
[CanBeNull]
349-
public Lazy<ImageResult> Detailed { get; internal set; }
350-
351-
// todo: maybe lazy list? i.e., each item is a lazy load
349+
public ImageResult FirstDetailed { get; internal set; }
350+
352351
}
353352

354353
public sealed class ResultCompletedEventArgs : EventArgs

SmartImage.Lib/Searching/ImageResult.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,6 @@ public float? MegapixelResolution
130130
/// </summary>
131131
public DisplayResolutionType DisplayResolution
132132
{
133-
134133
get
135134
{
136135
if (HasImageDimensions) {
@@ -139,7 +138,6 @@ public DisplayResolutionType DisplayResolution
139138

140139
throw new SmartImageException("Resolution unavailable");
141140
}
142-
143141
}
144142

145143
public ResultQuality Quality { get; set; }
@@ -204,8 +202,9 @@ public void UpdateFrom(ImageResult result)
204202

205203
public async void FindDirectImages()
206204
{
207-
if (Url == null || Direct != null)
205+
if (Url == null || Direct != null) {
208206
return;
207+
}
209208

210209
try {
211210

@@ -215,8 +214,6 @@ public async void FindDirectImages()
215214

216215
if (direct != null) {
217216
Direct = new Uri((direct));
218-
219-
Debug.WriteLine($"Found direct images");
220217
}
221218
}
222219
catch {

SmartImage/Program.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,11 @@ private static async Task Main(string[] args)
209209
}
210210
};
211211

212+
Client.DirectFound += (sender, eventArgs) =>
213+
{
214+
215+
};
216+
212217
ConsoleProgressIndicator.Start(_cancellationToken);
213218

214219

0 commit comments

Comments
 (0)