I have created a signalR hub which is solving purpose to show timer at UI of grouped person. If one person starts a play with another one, timer runs very nice.
But the problem is when another group start a new play and previous one is still in progress, I mean Timer is already running, then it overlaps the timer and hold one group. Timer runs once at a time. But I want it to have threading and run for every group.
here is my code:
ConnectionMapping.cs
public class ConnectionMapping<T>
{
private readonly Dictionary<T, HashSet<string>> _connections = new Dictionary<T, HashSet<string>>();
public int Count { get { return _connections.Count; } }
public void Add(T key, string connectionId)
{
lock (_connections)
{
HashSet<string> connections;
if (!_connections.TryGetValue(key, out connections))
{
connections = new HashSet<string>();
_connections.Add(key, connections);
}
lock (connections)
{
connections.Add(connectionId);
}
}
}
public IEnumerable<string> GetConnections(T key)
{
HashSet<string> connections;
if (_connections.TryGetValue(key, out connections))
{
return connections;
}
return Enumerable.Empty<string>();
}
public void Remove(T key, string connectionId)
{
lock (_connections)
{
HashSet<string> connections;
if (!_connections.TryGetValue(key, out connections))
{
return;
}
lock (connections)
{
connections.Remove(connectionId);
if (connections.Count == 0)
{
_connections.Remove(key);
}
}
}
}
}
Below is a Hub class:
public class TimeSyncingHub : Hub
{
private readonly static ConnectionMapping<int> _connections = new ConnectionMapping<int>();
private readonly PlayerPickTicker _playerPickTicker;
private readonly object _PickStateLock = new object();
private IUserBusiness userBusiness;
public TimeSyncingHub() :
this(PlayerPickTicker.Instance)
{
}
public TimeSyncingHub(PlayerPickTicker playerPickTicker)
{
_playerPickTicker = playerPickTicker;
}
public Task LeaveRoom(string roomName)
{
return Groups.Remove(Context.ConnectionId, roomName);
}
public async Task JoinRoom(string roomName)
{
await Groups.Add(Context.ConnectionId, roomName);
Clients.Group(roomName).JoinedRoom("Enter into group - " + roomName);
}
}
Another class where I have written time code is PlayerPickTicker class which is depends in same and implemented in constructor of hub class as shown in class above.
Below is PlayerPickTicker class:
public class PlayerPickTicker : IDisposable
{
private readonly static Lazy<PlayerPickTicker> _instance = new Lazy<PlayerPickTicker>(
() => new PlayerPickTicker(GlobalHost.ConnectionManager.GetHubContext<TimeSyncingHub>()));
private IHubContext _context;
public UserPlayerPickModel UserPlayerPick { get; set; }
public static PlayerPickTicker Instance { get { return _instance.Value; } }
private Timer TickTimer;
private Timer InitialTickTimer;
public int StartSeconds { get; set; }
public int StopSeconds { get; set; }
public bool IsTimerOver { get; set; }
private PlayerPickTicker(IHubContext context)
{
_context = context;
}
public void StartInitialTimer(Model.QueryModel queryModel)
{
try
{
MyDraftBusiness myDraft = new MyDraftBusiness();
myDraft.UdpatePlaysOneMinuteTimerPending(queryModel);
//lock (_InitialTimerStateLock)
//{
//StartSeconds = 60;
//if (InitialTickTimer != null)
//{
// InitialTickTimer.Dispose();
//}
States = new Dictionary<string, bool>() {
{ "IsInitialTimerOver", false},
{ "CallInitialTimerOverMethod", true},
};
PickPlayer = new Dictionary<string, long>() { { "LastPlayerPickId", 0 } };
//lock (States)
//{
StartSeconds = 60;
StopSeconds = 0;
IsInitialTimerOver = false;
CallInitialTimerOverMethod = true;
//}
InitialTickTimer = new Timer();// OnTimerElapsedInitialTimer, queryModel, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1));
InitialTickTimer.Interval = 1000;
InitialTickTimer.Enabled = true;
InitialTickTimer.Elapsed += (sender, e) => OnTimerElapsedInitialTimer(queryModel, e);
InitialTickTimer.AutoReset = false;
//}
//}
}
catch (Exception ex)
{
Helpers.ExceptionsLog.LogFile(" -( At StartInitialTimer Mehtod )- " + ex.Message);
}
}
private void OnTimerElapsedInitialTimer(object sender, ElapsedEventArgs e)
{
Model.QueryModel queryModel = (Model.QueryModel)sender;
try
{
//lock (_InitialtickStateLock)
//{
var states = (Dictionary<string, bool>)States;
var IsInitialTimerOver = states.FirstOrDefault(x => x.Key == "IsInitialTimerOver").Value;
//Clients.
if (StartSeconds <= StopSeconds && !IsInitialTimerOver)
{
if (InitialTickTimer != null)
{
InitialTickTimer.Dispose();
}
//IsInitialTimerOver = true;
states["IsInitialTimerOver"] = true;
//lock (States)
//{
//************** from client to server
var JsonResult = new JObject();
JsonResult.Add("data", JToken.FromObject(queryModel));
string GroupName = "Group" + queryModel.playId.ToString();
_context.Clients.Group(GroupName).initialTimerCompleted(JsonResult);
//_context.Clients.Group(GroupName, _context.Clients.All).initialTimerCompleted(JsonResult);
//_context.Clients.All.initialTimerCompleted(JsonResult);
MyDraftBusiness myDraft = new MyDraftBusiness();
try
{
myDraft.UdpatePlaysOneMinuteTimerRunning(queryModel);
DraftModel draftModel = myDraft.GetDraftById(queryModel);
if (draftModel != null)
{
var userPlayerPicks = myDraft.GetUserPlayerPickByPlayId(draftModel.PlayId);
if (draftModel.IsDraftFilled)
{
if (draftModel.Play != null && draftModel.Play.IsOneMinuteTimerPending == true)
{
myDraft.UdpatePlaysOneMinuteTimerPending(queryModel);
}
else
{
var activeUserPick = userPlayerPicks.Where(x => !x.Picked).FirstOrDefault();
if (activeUserPick != null)
{
StartTimer(activeUserPick);
}
}
}
}
}
catch (Exception ex)
{
Helpers.ExceptionsLog.LogFile(" -( At OnTimerElapsedInitialTimer Mehtod inner catch )- " + ex.Message);
var userPlayerPicks = myDraft.GetUserPlayerPickByPlayId(queryModel.playId);
var activeUserPick = userPlayerPicks.Where(x => !x.Picked).FirstOrDefault();
if (activeUserPick != null)
{
StartTimer(activeUserPick);
}
}
//}
}
else if (StartSeconds > 0)
{
//IsInitialTimerOver = false;
states["IsInitialTimerOver"] = false;
//lock (States)
//{
StartSeconds -= 1;
var GroupName = "Group" + Convert.ToString(queryModel.playId);
_context.Clients.Group(GroupName).intialTimerElapsed(StartSeconds);
_context.Clients.All.pickRunning(queryModel.playId);
InitialTickTimer.Stop();
InitialTickTimer.Start();
//StartInitialTimer(queryModel);
//}
}
//}
}
catch (Exception ex)
{
Helpers.ExceptionsLog.LogFile(" -( At OnTimerElapsedInitialTimer Mehtod )- " + ex.Message);
}
}
I know it's big code and hard to understand. But I hope for Any Good Developer here, Much appreciation for helper from core of my heart!
Related
Im using Xamarin Forms Maps and I implemented location button:
Map.IsShowingUser = true;
Also I added Permissions (Xamarin Essentials nuget) and implemented like this in my view model:
public class MapViewModel : BaseViewModel
{
public MapViewModel(CustomMap map)
{
Map = map;
GetPermissions();
Task.Run(async () => { await GetImage(); });
}
public void SetPins()
{
if (App.FilterPins != null && App.FilterPins.Count > 0)
{
Device.BeginInvokeOnMainThread(() =>
{
Map.CustomPins.Clear();
Map.CustomPins.AddRange(App.FilterPins);
foreach (var item in App.FilterPins)
{
Map.Pins.Add(item);
App.SelectedPin = item;
item.InfoWindowClicked += Pin_InfoWindowClicked;
}
Map.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(App.SelectedPin.Position.Latitude, App.SelectedPin.Position.Longitude), Distance.FromMiles(1.0)));
OnPropertyChanged(nameof(Map.CustomPins));
OnPropertyChanged(nameof(Map));
});
}
else
{
GetMapDefaultData();
}
}
public void SetMapToSelectedPin()
{
Device.BeginInvokeOnMainThread(() =>
{
if (App.SelectedPin != null)
{
//gledam da li je u listi pinova App.FilterPins ili u DefaultPins (iz default servisa)
if (Map.CustomPins.Any(x => x.Id == App.SelectedPin.Id))
{
//focusOnPin
Map.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(App.SelectedPin.Position.Latitude, App.SelectedPin.Position.Longitude), Distance.FromMiles(1.0)));
}
else
{
//add pin to list -> Map.Pins.Add(pin);
//focusonpin
if (App.FilterPins != null && App.FilterPins.Count > 0)
{
Map.CustomPins.Add(App.SelectedPin);
Map.Pins.Add(App.SelectedPin);
Map.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(App.SelectedPin.Position.Latitude, App.SelectedPin.Position.Longitude), Distance.FromMiles(1.0)));
}
}
}
else
{
Map.MoveToRegion(MapSpan.FromCenterAndRadius(Constants.BelgradeCoordinates, Distance.FromMiles(1.0)));
}
OnPropertyChanged(nameof(Map));
});
}
private async Task GetImage()
{
App.PinImages = new List<PinImageResponseModel>();
var result = await ApiServiceProvider.GetPinImages();
Device.BeginInvokeOnMainThread(() =>
{
App.PinImages = result;
});
}
public CustomPin _pin { get; set; }
public CustomPin Pin
{
get { return _pin; }
set { _pin = value; OnPropertyChanged(); }
}
public ICommand PositionMapOnPinCommand { get; set; }
private async void GetMapDefaultData()
{
try
{
DefaultRegionsAndClassesResponseModel regionsAndPinsResponse = new DefaultRegionsAndClassesResponseModel();
#region Regions
var regions = await ApiServiceProvider.GetRegionsQuery(null, 0, 5000);
//if (regions != null && regions.Data != null)
//{
// var polygon = new Polygon();
// foreach (var region in regions.Data.Where(x => x.Checked).ToList())
// {
// polygon.StrokeWidth = 8;
// polygon.StrokeColor = Color.Green;
// polygon.FillColor = Color.FromRgba(255, 0, 0, 64);
// foreach (var point in region.Points)
// {
// polygon.Geopath.Add(new Position(point.Latitude, point.Longitude));
// }
// Map.MapElements.Add(polygon);
// }
//}
#endregion
#region Pins & Infoboxes
regionsAndPinsResponse = await ApiServiceProvider.GetDefaultRegionsAndClasses();
Device.BeginInvokeOnMainThread(() =>
{
if (regionsAndPinsResponse.Succeeded && regionsAndPinsResponse.Data != null && regionsAndPinsResponse.Data.Count > 0)
{
foreach (var mainItem in regionsAndPinsResponse.Data)
{
CustomPin pin = new CustomPin();
if (mainItem != null && mainItem.Points.Count > 0)
{
pin.Id = mainItem.IdObjectInstance;
pin.ClassId = mainItem.ObjectClassIdObjectClass;
pin.Label = mainItem.ObjectClassName;
pin.IsFavorite = mainItem.IsFavorite.HasValue;
foreach (var item in App.PinImages)
{
if (mainItem.Status != null && mainItem.Status.ClassStatus.ClassStatusIcon != null && item.Name.Equals(mainItem.Status.ClassStatus.ClassStatusIcon))
{
string base64 = item.Base64String.Substring(item.Base64String.IndexOf(',') + 1);
base64 = base64.Trim('\0');
pin.InfoBox.ImageString = base64;
if (pin.InfoBox.ImageString != null)
{
var source = Convert.FromBase64String(pin.InfoBox.ImageString);
pin.InfoBox.PinImageSource = ImageSource.FromStream(() => new MemoryStream(source));
}
}
}
if (mainItem.Points != null)
{
pin.Position = new Position(mainItem.Points.FirstOrDefault().Latitude, mainItem.Points.FirstOrDefault().Longitude);
}
else
{
//add polygon
}
foreach (var item in mainItem.Strings)
{
pin.InfoBox.DetailsObjectInfos.Add(new Models.MapModels.DetailsObjectInfo { BoldLabelTitle = item.ClassParameterName + ": ", LabelValue = item.StringValue });
}
foreach (var item in mainItem.Integers)
{
pin.InfoBox.DetailsObjectInfos.Add(new Models.MapModels.DetailsObjectInfo { BoldLabelTitle = item.ClassParameterName + ": ", LabelValue = item.IntValue.ToString() });
}
}
pin.InfoWindowClicked += Pin_InfoWindowClicked;
Map.CustomPins.Add(pin);
Map.Pins.Add(pin);
}
}
});
#endregion
}
catch (Exception ex)
{
await Shell.Current.DisplayAlert("Error", "Something went wrong with maps", "OK");
}
}
private void Pin_InfoWindowClicked(object sender, PinClickedEventArgs e)
{
Device.BeginInvokeOnMainThread(async () =>
{
var pin = sender as CustomPin;
App.SelectedPin = pin;
await Shell.Current.Navigation.PushAsync(new ObjectParametersPage());
});
}
private async void GetPermissions()
{
var status = await Permissions.CheckStatusAsync<Permissions.LocationWhenInUse>();
if (status != PermissionStatus.Granted)
{
status = await Permissions.RequestAsync<Permissions.LocationWhenInUse>();
}
if (status == PermissionStatus.Granted)
{
Map.IsShowingUser = true;
}
else
{
await Shell.Current.DisplayAlert("Permission Denied", "We Need to access your Location. But it is not granted", "OK");
}
}
public CustomMap Map { get; set; }
public ICommand SetCameraToChosenPinCommand { get; set; }
}
My XAML:
</ContentPage>
<ContentPage.Content>
<renderers:CustomMap x:Name="map" IsShowingUser="True"/>
</ContentPage.Content>
</ContentPage>
CodeBehind:
public partial class MapPage : ContentPage
{
MapViewModel mapViewModel;
public MapPage()
{
InitializeComponent();
BindingContext = mapViewModel = new MapViewModel(map);
}
protected override void OnAppearing()
{
base.OnAppearing();
mapViewModel.SetPins();
mapViewModel.SetMapToSelectedPin();
}
}
my CustomMap:
public class CustomMap : Map
{
//public List<CustomPin> CustomPins { get; set; }
public CustomMap()
{
CustomPins = new ObservableCollection<CustomPin>();
CustomPins.CollectionChanged += PinsSourceOnCollectionChanged;
}
public ObservableCollection<CustomPin> CustomPins
{
get { return (ObservableCollection<CustomPin>)GetValue(PinsSourceProperty); }
set { SetValue(PinsSourceProperty, value); OnPropertyChanged(nameof(CustomPins)); }
}
public static readonly BindableProperty PinsSourceProperty = BindableProperty.Create(
propertyName: "PinsSource",
returnType: typeof(ObservableCollection<CustomPin>),
declaringType: typeof(CustomMap),
defaultValue: null,
defaultBindingMode: BindingMode.TwoWay,
validateValue: null,
propertyChanged: PinsSourcePropertyChanged);
public MapSpan MapSpan
{
get { return (MapSpan)GetValue(MapSpanProperty); }
set { SetValue(MapSpanProperty, value); }
}
public static readonly BindableProperty MapSpanProperty = BindableProperty.Create(
propertyName: "MapSpan",
returnType: typeof(MapSpan),
declaringType: typeof(CustomMap),
defaultValue: null,
defaultBindingMode: BindingMode.TwoWay,
validateValue: null,
propertyChanged: MapSpanPropertyChanged);
private static void MapSpanPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
var thisInstance = bindable as CustomMap;
var newMapSpan = newValue as MapSpan;
thisInstance?.MoveToRegion(newMapSpan);
}
private static void PinsSourcePropertyChanged(BindableObject bindable, object oldvalue, object newValue)
{
var thisInstance = bindable as CustomMap;
var newPinsSource = newValue as ObservableCollection<CustomPin>;
if (thisInstance == null ||
newPinsSource == null)
return;
UpdatePinsSource(thisInstance, newPinsSource);
}
private void PinsSourceOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
UpdatePinsSource(this, sender as IEnumerable<CustomPin>);
}
private static void UpdatePinsSource(CustomMap bindableMap, IEnumerable<CustomPin> newSource)
{
bindableMap.IsShowingUser = true;
bindableMap.Pins.Clear();
foreach (var pin in newSource)
bindableMap.Pins.Add(pin);
}
}
So, I have a bug only on first time installing app on my phone - it doesnt show location button, because its async method.
Each next tiem when I open the Map page there is a button.
So, my question would be: how to properly integrate permissions and map, in order to present location button on the first startup of application?
I created a reference to load big data into a datagrid with a dapper extension. I have a Behavior that detects when the scroll is then down load the following data using this RelayCommand:
XAML in Datagrid Properties :
Behavior:ScrollViewerMonitor.AtEndCommand="{Binding LoadCommand}"
My Behavior (Detect when scroll is down) :
public class ScrollViewerMonitor
{
public static DependencyProperty AtEndCommandProperty
= DependencyProperty.RegisterAttached(
"AtEndCommand", typeof(ICommand),
typeof(ScrollViewerMonitor),
new PropertyMetadata(OnAtEndCommandChanged));
public static ICommand GetAtEndCommand(DependencyObject obj)
{
return (ICommand)obj.GetValue(AtEndCommandProperty);
}
public static void SetAtEndCommand(DependencyObject obj, ICommand value)
{
obj.SetValue(AtEndCommandProperty, value);
}
public static void OnAtEndCommandChanged(
DependencyObject d, DependencyPropertyChangedEventArgs e)
{
FrameworkElement element = (FrameworkElement)d;
if (element != null)
{
element.Loaded -= element_Loaded;
element.Loaded += element_Loaded;
}
}
static void element_Loaded(object sender, RoutedEventArgs e)
{
FrameworkElement element = (FrameworkElement)sender;
element.Loaded -= element_Loaded;
ScrollViewer scrollViewer = FindChildOfType<ScrollViewer>(element);
if (scrollViewer == null)
{
// throw new InvalidOperationException("ScrollViewer not found.");
return;
}
var dpd = DependencyPropertyDescriptor.FromProperty(ScrollViewer.VerticalOffsetProperty, typeof(ScrollViewer));
dpd.AddValueChanged(scrollViewer, delegate (object o, EventArgs args)
{
bool atBottom = scrollViewer.VerticalOffset
>= scrollViewer.ScrollableHeight;
if (atBottom)
{
var atEnd = GetAtEndCommand(element);
if (atEnd != null)
{
atEnd.Execute(null);
}
}
});
}
static T FindChildOfType<T>(DependencyObject root) where T : class
{
var queue = new Queue<DependencyObject>();
queue.Enqueue(root);
while (queue.Count > 0)
{
DependencyObject current = queue.Dequeue();
for (int i = VisualTreeHelper.GetChildrenCount(current) - 1; 0 <= i; i--)
{
var child = VisualTreeHelper.GetChild(current, i);
var typedChild = child as T;
if (typedChild != null)
{
return typedChild;
}
queue.Enqueue(child);
}
}
return null;
}
}
My ViewModel with LoadCommand :
//Init mmy ObservableCollection for DataGrid
var myObservableCollection = new ObservableCollection<Mouvement_Brouillard>();
//Init my Object
//Parameters(NumberPerPage,Conditions,OrderBy,Connection)
var myReference = new Paged2<Mouvement_Brouillard>(150, "", "Swmo_Id", new ConnectionProvider());
//Load First Datas
myReference.AddDatas(myObservableCollection);
//Call LoadCommand when Scroll is down
LoadCommand = new RelayCommand<object>(myReference.LoadCommand(myObservableCollection));
And my reference Paged2 (AddData in ObservableCollection and execute LoadCommand:
public class Paged2<T>
{
private T Value { get; set; }
public int NumberPage { get; set; }
public int RowsPerPage { get; set; }
public string Conditions { get; set; }
public string OrderBy { get; set; }
public ConnectionProvider Cnn { get; set; }
public static bool Busy;
public Paged2(int _RowsPerPage, string _Conditions, string _OrdeBy, ConnectionProvider _Cnn)
{
this.RowsPerPage = _RowsPerPage;
this.Conditions = _Conditions;
this.OrderBy = _OrdeBy;
this.NumberPage = 1;
this.Cnn = _Cnn;
}
public async void AddDatas(ObservableCollection<T> myList)
{
IEnumerable<T> myNewBlocList;
//DAL
using (var myCnn = this.Cnn.GetOpenConnection())
{
myNewBlocList = await myCnn.GetListPagedAsync<T>(this.NumberPage, this.RowsPerPage, this.Conditions, this.OrderBy);
}
NumberPage++;
foreach (var Item in myNewBlocList)
myList.Add(Item);
}
public Action<object> LoadCommand(Ref<ObservableCollection<T>> myList)
{
return new Action<object>(
obj =>
{
if (Busy)
return;
Busy = true;
System.Threading.ThreadPool.QueueUserWorkItem(
delegate
{
Application.Current.Dispatcher.BeginInvoke(new Action(
delegate
{
AddDatas(myList);
Busy = false;
}));
});
});
}
public class Ref<T>
{
public Ref() { }
public Ref(T value) { Value = value; }
public T Value { get; set; }
public override string ToString()
{
T value = Value;
return value == null ? "" : value.ToString();
}
public static implicit operator T(Ref<T> r) { return r.Value; }
public static implicit operator Ref<T>(T value) { return new Ref<T>(value); }
}
}
Everything works but since I outsource (place in another file ) method LoadCommand the next part of the code no longer works :
public Action<object> LoadCommand(Ref<ObservableCollection<T>> myList)
{
return new Action<object>(
obj =>
{
if (Busy)
return;
Busy = true;
System.Threading.ThreadPool.QueueUserWorkItem(
delegate
{
Application.Current.Dispatcher.BeginInvoke(new Action(
delegate
{
AddDatas(myList);
Busy = false;
}));
});
});
}
I have two task which work as producer and consumer, but they don't run in parallel. Second one waits for the first one to compelete. Can you explain why and how can I correct this? I want both of them run at the same time. (I try many varians, but all of them don't work well)
class DirectoryReader
{
private readonly string _dir ;
private Processor[] _processors;
private string[] _files;
private readonly Regex _rx = new Regex(#"([^.\\]+)\.cs");
private Queue<Processor> queue = new Queue<Processor>();
private bool isOff;
private AutoResetEvent isAvailable = new AutoResetEvent(false);
private StreamWriter log = new StreamWriter("Log.txt");
public DirectoryReader(string dir)
{
_dir = dir;
}
public Container[] ProcessAllFiles()
{
_files = Directory.GetFiles(_dir, "*.cs", SearchOption.AllDirectories);
_processors = new Processor[_files.Length];
var thread = Task.Run(() => Compute());
var thread2 = Task.Run(() => Read());
thread.Wait();
}
public void Read()
{
for (var i = 0; i < _files.Length; i++)
{
try
{
var matches = _rx.Matches(_files[i]);
foreach (var match in matches)
{
//Console.WriteLine(match);
lock (log)
{
log.WriteLine(match);
}
}
_processors[i] = new Processor(matches[matches.Count - 1].ToString(), File.ReadAllText(_files[i]));
lock (queue)
{
queue.Enqueue(_processors[i]);
isAvailable.Set();
}
}
catch (IOException ex)
{
Console.WriteLine(ex.Message + _files[i]);
}
}
isOff = true;
}
public void Compute()
{
Processor proc = null;
int ccount = 0;
while (true)
{
lock (queue)
{
if ((ccount = queue.Count) > 0)
{
proc = queue.Dequeue();
}
}
if (ccount == 0)
{
if (isOff)
{
return;
}
else
{
isAvailable.WaitOne();
}
}
if (proc != null)
{
//Some calculations on proc
lock (log)
{
log.WriteLine("+++++" + proc.FileName);
}
}
}
}
}
UPD1: I rewrite this code with using BlockingCollection, but is still doesn't work correct
class DirectoryReader
{
private readonly string _dir ;
private Processor[] _processors;
private string[] _files;
private readonly Regex _rx = new Regex(#"([^.\\]+)\.cs");
private List<Container> answer = new List<Container>();
BlockingCollection<FileContainer> dataItems = new BlockingCollection<FileContainer>();
public DirectoryReader(string dir)
{
_dir = dir;
}
public void ProcessAllFiles()
{
_files = Directory.GetFiles(_dir, "*.cs", SearchOption.AllDirectories);
_processors = new Processor[_files.Length];
var task = Task.Factory.StartNew(Compute);
var task2 = Task.Factory.StartNew(Read);
Task.WaitAll(task, task2);
}
public void Read()
{
for (var i = 0; i < _files.Length; i++)
{
try
{
var matches = _rx.Matches(_files[i]);
dataItems.Add(new FileContainer{
Name = matches[matches.Count - 1].ToString(),
Content = File.ReadAllText(_files[i])});
}
catch (IOException ex)
{
Console.WriteLine(ex.Message + _files[i]);
}
}
dataItems.CompleteAdding();
}
public void Compute()
{
FileContainer proc = null;
while (!dataItems.IsCompleted)
{
try
{
proc = dataItems.Take();
}
catch (InvalidOperationException) { }
if (proc != null)
{
//Some calculations
}
}
}
}
I have written some test for repository I have wrote.
public interface IEntity<T> {
T Id { get; set; }
}
public abstract class Entity<TEntity> : IEntity<TEntity> {
[BsonId]
public TEntity Id { get; set; }
public override string ToString() {
return JsonConvert.SerializeObject(this, Formatting.Indented, new JsonSerializerSettings {
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
});
}
}
public interface IMongoRepository<TEntity, TE> : IQueryable<TEntity> where TEntity : IEntity<TE> {
string ConnectionString { get; set; }
bool Remove<T>(TEntity entity);
bool Save<T>(TEntity entity);
bool Update<T>(TEntity entity);
}
public sealed class MongoRepository<TEntity, TU> : IMongoRepository<TEntity, TU>
where TEntity : Entity<TU> {
public MongoCollection<TEntity> Collection {
get {
var client = new MongoClient(ConnectionString);
var server = client.GetServer();
var db = server.GetDatabase("mykantina");
return db.GetCollection<TEntity>(typeof (TEntity).Name.Pluralize());
}
}
private IQueryable<TEntity> Queryable {
get { return Collection.FindAll().AsQueryable(); }
}
#region IRepository<T,U> Implementation
public string ConnectionString { get; set; }
public bool Remove<T>(TEntity entity) {
try {
var e = entity as Entity<TU>;
if (e == null) return false;
WriteConcernResult resultConcern = Collection.Remove(Query.EQ("_id", e.Id.ToBson()));
return true;
}
catch (Exception e) {
return false;
}
}
public bool Save<T>(TEntity entity) {
try {
WriteConcernResult resultConcern = Collection.Save(entity);
return true;
}
catch (Exception e) {
return false;
}
}
public bool Update<T>(TEntity entity) {
throw new NotImplementedException();
}
#endregion
#region IQueryable<T> Implementation
public IEnumerator<TEntity> GetEnumerator() {
return Queryable.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() {
return Queryable.GetEnumerator();
}
public Type ElementType {
get { return Queryable.ElementType; }
}
public Expression Expression {
get { return Queryable.Expression; }
}
public IQueryProvider Provider {
get { return Queryable.Provider; }
}
#endregion
}
Here are the tests:
[Test]
public void LinearInsertsToMongoDb() {
Stopwatch total = Stopwatch.StartNew();
for (int i = 0; i <= 100000; i++) {
Stopwatch sw = Stopwatch.StartNew();
var isOk = _repository.Save<Widget>(new Widget {
Name = "Calendar" + i
});
sw.Stop();
Trace.WriteLine(string.Format("Took to insert {0}ms - item {1}", sw.ElapsedMilliseconds, i));
}
Trace.WriteLine(string.Format("================================================================"));
total.Stop();
Trace.WriteLine(string.Format("Total = {0}ms", total.ElapsedMilliseconds));
}
Time result: Total = 212398ms
private static object _sync = new object();
[Test]
public void ConcurrentInsertsToMongoDb() {
Stopwatch total = Stopwatch.StartNew();
var waitHandlers = new List<WaitHandle>();
for (int i = 0; i < 50; i++) {
var threadFinish = new EventWaitHandle(false, EventResetMode.ManualReset);
waitHandlers.Add(threadFinish);
var thread = new Thread(() => {
RunMongoThread();
threadFinish.Set();
});
thread.Start();
}
WaitHandle.WaitAll(waitHandles: waitHandlers.ToArray());
Trace.WriteLine(string.Format("================================================================"));
total.Stop();
Trace.WriteLine(string.Format("Total = {0}ms", total.ElapsedMilliseconds));
}
private static void RunMongoThread() {
for (var i = 0; i < 300; i++) {
bool isLocked = false;
try {
Monitor.Enter(_sync, ref isLocked);
var widget = new Widget {
Name = "Calendar" + i
};
var isOk = _repository.Save<Widget>(widget);
Trace.WriteLine(string.Format("Object: {0} - Thread {1}", widget, Thread.CurrentThread.ManagedThreadId));
}
finally {
if(isLocked)
Monitor.Exit(_sync);
}
}
}
Time result: Total 31303ms
The question what I'm doing wrong and why it's so slow?
I'm working on a network monitoring application, that pings a (not known) number of hosts. So far I have the code below. I've made a class PingHost with a function zping and I called it with the help of a timer once every 2 seconds to let the 2 pings to finish, even if one of them gets TimedOut. But I think a better solution is to generate a new thread for every ping, so that the ping of every host would be independent.
Can anyone give me a hint how to do this?
namespace pinguin
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void timer1_Tick(object sender, EventArgs e)
{
PingHost caca = new PingHost();
PingHost caca1 = new PingHost();
this.label1.Text = caca.zping("89.115.14.160");
this.label2.Text = caca1.zping("89.115.14.129");
}
}
public class PingHost
{
public string zping(string dest)
{
Application.DoEvents();
Ping sender = new Ping();
PingOptions options = new PingOptions();
options.DontFragment = true;
string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
byte[] buffer = Encoding.ASCII.GetBytes(data);
int timeout = 50;
int failed = 0;
int pingAmount = 5;
string stat = "";
PingReply reply = sender.Send(dest, timeout, buffer, options);
if (reply.Status == IPStatus.Success)
{
stat = "ok";
}
else
{
stat = "not ok!";
}
return stat;
}
}
}
If you use .NET 4 you can use Parallel.Invoke.
You could handle the Ping.PingCompleted event:
ping.PingCompleted += new PingCompletedEventHandler(ping_PingCompleted);
then use:
ping.SendAsync()
side note: Choose more suitable names for your classes and routines. PingHost is more suitable as a routine name
Once I wrote such a solution (it constantly pings about 300 machines):
public class ManyAdressPing {
private readonly bool bAutoStarted;
private readonly CancellationTokenSource cancel = new CancellationTokenSource();
public ConcurrentDictionary<IPAddress, OneAddressPing> pingi = new ConcurrentDictionary<IPAddress, OneAddressPing>();
public ManyAdressPing(bool AutoStarted = true) {
bAutoStarted = AutoStarted;
}
public int CountPings => pingi.Count;
public void AddPingAddress(IPAddress addr, int msTimeOut = 3000, int BetweenPing = 3000) {
var oap = new OneAddressPing(addr, cancel.Token, msTimeOut, BetweenPing);
if (bAutoStarted) oap.Start();
pingi.TryAdd(oap.ipAddress, oap);
}
public void RemovePingAddress(IPAddress addr) {
if (pingi.TryRemove(addr, out var p)) p.Stop();
}
public void Stop() {
cancel.Cancel();
foreach (var pair in pingi) pair.Value.Stop();
}
public PingReply GetReply(IPAddress addr) {
if (pingi.ContainsKey(addr)) return pingi[addr].GetReply();
return null;
}
public Tuple<long, long> GetSuccessOperation(IPAddress addr) {
if (pingi.ContainsKey(addr)) return pingi[addr].GetSuccessOperation();
return null;
}
public PingReply[] GetReply() {
PingReply[] ret = pingi.Values.Select(x=>x.GetReply()).ToArray();
return ret;
}
public PingInfo GetPingInfo(IPAddress addr) {
if (pingi.ContainsKey(addr)) {
var ret = new PingInfo();
var p = pingi[addr];
ret.reply = p.GetReply();
ret.SuccessPing = p._SuccessReply;
ret.FailPing = p._FailReply;
ret.LastSuccessPing = p.LastSuccessfullPing;
return ret;
}
return null;
}
public bool IsPinged(IPAddress addr) {
if (pingi.ContainsKey(addr)) return true;
return false;
}
public IPAddress[] GetAddressesPing() {
return pingi.Keys.ToArray();
}
}
public class PingInfo {
public PingReply reply;
public long SuccessPing = 0;
public long FailPing = 0;
public DateTime LastSuccessPing;
public override string ToString() {
return $"Sping: {SuccessPing} last={LastSuccessPing}, Fping:{FailPing}, reply:{reply}";
}
}
public class OneAddressPing {
public static byte[] bu = {
0
};
public long _FailReply;
public long _SuccessReply;
private bool bStop = false;
private readonly CancellationToken cancellationToken;
public DateTime LastSuccessfullPing = DateTime.MinValue;
public int mSecBetweenPing = 3000;
public Ping ping;
public PingOptions popt;
private Task pTask;
// Here is a self-written LIFO stack
public LightQueue<PingReply> replys = new LightQueue<PingReply>(10);
private readonly AutoResetEvent reset = new AutoResetEvent(false);
private Logger log = null;
private Task pinging = null;
public OneAddressPing(IPAddress addr, CancellationToken ct, int timeOut = 3000, int BetweenPing = 3000, Logger _log =null) {
ipAddress = addr;
popt = new PingOptions();
popt.DontFragment = false;
cancellationToken = ct;
mSecTimeOut = timeOut;
mSecBetweenPing = BetweenPing;
log = _log;
}
public int mSecTimeOut { get; set; } = 3000;
public IPAddress ipAddress { get; set; }
public int CountPings => replys.Length;
private void SetReply(PingReply rep) {
if (rep == null) return;
replys.Put(rep);
if (rep.Status == IPStatus.Success) {
Interlocked.Increment(ref _SuccessReply);
LastSuccessfullPing = DateTime.Now;
} else {
Interlocked.Increment(ref _FailReply);
}
}
public async Task Start() {
if (pTask == null || pTask.Status != TaskStatus.Running) {
ping = new Ping();
Task.Factory.StartNew(PingCircle, TaskCreationOptions.RunContinuationsAsynchronously | TaskCreationOptions.LongRunning); pTask = Task.Run(PingCircle, cancellationToken);
}
}
public void Stop() {
if (pTask.Status == TaskStatus.Running) {
bStop = true;
try {
pTask.Wait(mSecTimeOut, cancellationToken);
} catch (Exception ex) {
log.ErrorSource($"Error ping stop: {ex.Message}");
}
}
}
private async Task PingCircle() {
while (cancellationToken.IsCancellationRequested == false && !bStop) {
try {
try {
PingReply rep = await ping.SendPingAsync(ipAddress, mSecTimeOut, bu,popt);
if (rep != null) SetReply(rep);
} catch (PingException p) {
// ignore ping error
Debug.WriteLine($"error: {p}");
} catch (Exception ee) {
log?.ErrorSource(ee);
Debug.WriteLine($"error: {ee}");
}
await Task.Delay(mSecBetweenPing, cancellationToken);
} catch (Exception ee) {
log?.ErrorSource(ee);
}
}
}
public PingReply GetReply() {
if (replys.IsEmpty) return null;
return replys.PeekLast(0);
}
public Tuple<long, long> GetSuccessOperation() {
return new Tuple<long, long>(_SuccessReply, _FailReply);
}
public bool LongPingSuccess() {
int ret = 0;
for (int i = 0; i < 5; i++) {
var r = replys.PeekLast(i);
if (r.Status == IPStatus.Success) ret++;
}
if (ret > 2) return true;
return false;
}
}