Skip to content

Commit

Permalink
Perf improvement: use a model that batch calls to RefreshObjects in t…
Browse files Browse the repository at this point in the history
…he view, use FastObjectListView
  • Loading branch information
fremag committed Nov 17, 2017
1 parent 3b20977 commit d2d5e06
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 33 deletions.
11 changes: 10 additions & 1 deletion Nats.Services.KeyValueStoreDemo/StoreClient/ProductInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,25 @@

namespace StoreClient
{
public class ProductInfo
public class ProductInfo : StoreRowItem<Product>
{
public Product Product { get; private set; }
public ProductInfo()
{

}
public ProductInfo(Product product)
{
Product = product;
LastUpdate = DateTime.Now;
}
public void Update(Product product)
{
if( Product == null)
{
Product = product;
return;
}
Product.Price = product.Price;
Product.Quantity= product.Quantity;
LastUpdate = DateTime.Now;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="StoreClientModel.cs" />
<Compile Include="StoreRowItem.cs" />
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 7 additions & 31 deletions Nats.Services.KeyValueStoreDemo/StoreClient/StoreClientForm.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
using BrightIdeasSoftware;
using Nats.Services.Core;
using Nats.Services.Core;
using Nats.Services.Core.DiscoveryService;
using NATS.Client;
using NLog;
using StoreServices;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
Expand All @@ -20,12 +17,11 @@ public partial class StoreClientForm : Form
IConnection connection;
NatsServiceFactory serviceFactory;
IProductStoreService storeService;
private List<ProductInfo> productInfos;
StoreClientModel<string, Product, ProductInfo> model = new StoreClientModel<string, Product, ProductInfo>();

public StoreClientForm()
{
InitializeComponent();
Generator.GenerateColumns(objectListView1, typeof(ProductInfo));
}

private async void StoreClientForm_LoadAsync(object sender, EventArgs e)
Expand All @@ -39,36 +35,16 @@ private async void StoreClientForm_LoadAsync(object sender, EventArgs e)
string serverName = await Task.Run(() => DiscoverServer(connection, logger));
logger.Info($"Server found: {serverName}.");
Text += serverName;
var products = await Task.Run(()=>InitServices(serverName));
logger.Info($"Store initialized: {products.Count}");
InitData(products);
await InitServicesAsync(serverName);
logger.Info($"Store initialized: {objectListView1.GetItemCount()}");
}

private List<Product> InitServices(string serverName)
private async Task InitServicesAsync(string serverName)
{
serviceFactory = new NatsServiceFactory(connection, serverName);
storeService = serviceFactory.BuildServiceClient<IProductStoreService>();
storeService.ValueUpdated += OnValueUpdated;
var products = storeService.GetAllValues();
return products;
}

private void OnValueUpdated(Product product)
{
if (productInfos == null) return;
var productInfo = productInfos.FirstOrDefault(pI => pI.Name == product.Name);
if( productInfo != null)
{
productInfo.Update(product);
objectListView1.RefreshObject(productInfo);
}
}

private void InitData(List<Product> products)
{
Text += $", {products.Count} products";
var tmp = products.Select(product => new ProductInfo(product)).ToList();
productInfos = tmp;
await model.InitAsync(storeService, objectListView1);
Text += $", {objectListView1.GetItemCount()} products";
}

public static string DiscoverServer(IConnection connection, ILogger logger=null, int periodMs=1000)
Expand Down
89 changes: 89 additions & 0 deletions Nats.Services.KeyValueStoreDemo/StoreClient/StoreClientModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
using BrightIdeasSoftware;
using Nats.Services.Core.KeyValueStoreService;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace StoreClient
{
public class StoreClientModel<T_Key, T_Value, T_RowItem>
where T_Value : IKeyIdentifiable<T_Key>
where T_RowItem : class, StoreRowItem<T_Value>, new()
{
IKeyValueStoreService<T_Key, T_Value> service;

Dictionary<T_Key, T_RowItem> dicoKeyRows = new Dictionary<T_Key, T_RowItem>();
Dictionary<T_Key, T_RowItem> updatedRows = new Dictionary<T_Key, T_RowItem>();
Timer timer;
ObjectListView view;

public async Task InitAsync(IKeyValueStoreService<T_Key, T_Value> service, ObjectListView view)
{
this.service = service;
this.view = view;

var items= await Task.Run(() => service.GetAllValues());
foreach(var item in items)
{
var rowItem = new T_RowItem();
rowItem.Update(item);
dicoKeyRows[item.Key] = rowItem;
}
Generator.GenerateColumns(view, typeof(T_RowItem));

view.Objects = dicoKeyRows.Values;
timer = new Timer();
timer.Tick += UpdateBatch;
timer.Start();
service.ValueUpdated += OnValueUpdated;
}

private void UpdateBatch(object sender, EventArgs evt)
{
List<T_RowItem> values;
lock (updatedRows)
{
if(updatedRows.Count == 0)
{
return;
}
values = updatedRows.Values.ToList();
updatedRows.Clear();
}
view.Invoke( (Action)(() => RefreshRows(values)));
}

Stopwatch sw = new Stopwatch();
long n = 0;
private void RefreshRows(List<T_RowItem> values)
{
n++;
sw.Start();
view.RefreshObjects(values);
sw.Stop();
if( n % 10 == 0)
{
Debug.WriteLine("n: " + n + ", t=" + sw.ElapsedMilliseconds + ", avg: " + (sw.ElapsedMilliseconds/ (double)n));
}
}

private void OnValueUpdated(T_Value obj)
{
lock(updatedRows)
{
T_RowItem rowItem;
if(! dicoKeyRows.TryGetValue(obj.Key, out rowItem))
{
rowItem = new T_RowItem();
dicoKeyRows[obj.Key] = rowItem;
}

rowItem.Update(obj);
updatedRows[obj.Key] = rowItem;
}
}
}
}
7 changes: 7 additions & 0 deletions Nats.Services.KeyValueStoreDemo/StoreClient/StoreRowItem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace StoreClient
{
public interface StoreRowItem<T_Value>
{
void Update(T_Value value);
}
}

0 comments on commit d2d5e06

Please sign in to comment.