I want to optimize My server side speed and performance to manage clients, I think I have two way to mange them:
1.Create manually one thread per client connection
2.create SynchronizationContext per client (this will manage threads on background)
Suppose We have one million users connected:
The first way is faster but I don't know is optimize and better way to manage send/receive data from client or not?
What is your suggestion to make better performance and speed to manage all of clients without lags and hangs?
My example to test SynchronizationContext and multi thread on console:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace SynchronizationContextForMethod
{
public class ServiceClass
{
public void Login(string name)
{
OperationContext<ClientInfo>.Current = new ClientInfo() { Name = name };
}
public string WhatIsMyName()
{
return OperationContext<ClientInfo>.Current.Name;
}
}
public class ClientInfo
{
public string Name { get; set; }
public string UserName { get; set; }
}
public class OperationContext<T>
{
static ConcurrentDictionary<SynchronizationContext, T> ContextByThread = new ConcurrentDictionary<SynchronizationContext, T>();
public static T Current
{
get
{
ContextByThread.TryGetValue(SynchronizationContext.Current, out T value);
return value;
}
set
{
ContextByThread.TryAdd(SynchronizationContext.Current, value);
}
}
public static void EncContext()
{
ContextByThread.TryRemove(SynchronizationContext.Current, out T value);
}
}
class Program
{
static List<SynchronizationContext> _contexts = new List<SynchronizationContext>();
static void Main(string[] args)
{
ThreadPool.GetMaxThreads(out int worker, out int ports);
ThreadPool.SetMaxThreads(int.MaxValue, int.MaxValue);
Console.WriteLine("thread count : " + Process.GetCurrentProcess().Threads.Count);
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
_contexts.Add(SynchronizationContext.Current);
var service = new ServiceClass();
for (int i = 0; i < 20; i++)
{
//PostWithNewThread((state) =>
PostNormally((state) =>
{
GC.Collect();
if (SynchronizationContext.Current == null)
{
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
}
else
{
//no run ever
}
Console.WriteLine("thread count : " + Process.GetCurrentProcess().Threads.Count);
var name = state.ToString();
service.Login(name);
var isTrue = name == service.WhatIsMyName();
if (!isTrue)
{
//if false this is wrong code!
}
Console.WriteLine($"service login {name}: " + isTrue);
Thread.Sleep(5000);
Console.WriteLine($"service " + name + " finished");
OperationContext<ClientInfo>.EncContext();
}, "ali" + i);
Console.WriteLine("thread count : " + Process.GetCurrentProcess().Threads.Count);
//PostWithNewThread((state) =>
PostNormally((state) =>
{
GC.Collect();
if (SynchronizationContext.Current == null)
{
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
}
else
{
//no run ever
}
Console.WriteLine("thread count : " + Process.GetCurrentProcess().Threads.Count);
var name = state.ToString();
service.Login(name);
var isTrue = name == service.WhatIsMyName();
if (!isTrue)
{
//if false this is wrong code!
}
Console.WriteLine($"service login {name}: " + isTrue);
Console.WriteLine($"service " + name + " finished");
OperationContext<ClientInfo>.EncContext();
}, "reza" + i);
Console.WriteLine("thread count : " + Process.GetCurrentProcess().Threads.Count);
//PostWithNewThread((state) =>
PostNormally((state) =>
{
GC.Collect();
if (SynchronizationContext.Current == null)
{
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
}
else
{
//no run ever
}
Console.WriteLine("thread count : " + Process.GetCurrentProcess().Threads.Count);
Thread.Sleep(2000);
var name = state.ToString();
service.Login(name);
var isTrue = name == service.WhatIsMyName();
if (!isTrue)
{
//if false this is wrong code!
}
Console.WriteLine($"service login {name}: " + (isTrue));
Console.WriteLine($"service " + name + " finished");
OperationContext<ClientInfo>.EncContext();
}, "hassan" + i);
}
Console.WriteLine("thread count : " + Process.GetCurrentProcess().Threads.Count);
while (true)
{
GC.Collect();
Thread.Sleep(1000);
Console.WriteLine("thread count : " + Process.GetCurrentProcess().Threads.Count);
}
}
public static void PostNormally(SendOrPostCallback run, object state)
{
SynchronizationContext.Current.Post(run, state);
}
public static void PostWithNewThread(SendOrPostCallback run, object state)
{
Thread thread = new Thread(() =>
{
run(state);
});
thread.IsBackground = true;
thread.Start();
}
}
}
Related
I'm trying to use firebase and Google linked login in a game made with Unity.
I tried the search method, but the editor freezes when I try to login in the first scene.
If I play in the editor, it doesn't progress.
When I tried in the second scene, I was logged in.
But then someone else worked. So I'm not sure about this.
What did I do wrong in the Google linked login process?
How do I debug the editor when it freeze?
I am not an English speaker. I am sorry that my English is strange.
This is the code I used. It's not much different from what I searched and found.
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.Design.Serialization;
using System.Linq;
using System.Threading.Tasks;
using Firebase;
using Firebase.Auth;
using Google;
using UnityEditor;
using UnityEngine;
using UnityEngine.Serialization;
using UnityEngine.UI;
public class GoogleSignInClass : MonoBehaviour
{
public Text infoText;
public string webClientId = "310848617796-nf5a9ds97humnn8nqv5gihmnnqg6j3g4.apps.googleusercontent.com";
private FirebaseAuth auth;
private GoogleSignInConfiguration configuration;
[SerializeField] private bool IsEditor = false;
[FormerlySerializedAs("Canvas")] [SerializeField] private GameStart Canvas;
private void Awake()
{
configuration = new GoogleSignInConfiguration { WebClientId = webClientId, RequestEmail = true, RequestIdToken = true };
CheckFirebaseDependencies();
if (Application.isEditor)
IsEditor = true;
}
private void CheckFirebaseDependencies()
{
FirebaseApp.CheckAndFixDependenciesAsync().ContinueWith(task =>
{
if (task.IsCompleted)
{
if (task.Result == DependencyStatus.Available)
auth = FirebaseAuth.DefaultInstance;
else
AddToInformation("Could not resolve all Firebase dependencies: " + task.Result.ToString());
}
else
{
AddToInformation("Dependency check was not completed. Error : " + task.Exception.Message);
}
});
}
public void SignInWithGoogle() { OnSignIn(); }
public void SignOutFromGoogle() { OnSignOut(); }
private void OnSignIn()
{
if (!IsEditor)
{
GoogleSignIn.Configuration = configuration;
GoogleSignIn.Configuration.UseGameSignIn = false;
GoogleSignIn.Configuration.RequestIdToken = true;
AddToInformation("Calling SignIn");
GoogleSignIn.DefaultInstance.SignIn().ContinueWith(OnAuthenticationFinished);
}
else
{
Canvas.GoMainMenu();
}
}
private void OnSignOut()
{
AddToInformation("Calling SignOut");
GoogleSignIn.DefaultInstance.SignOut();
}
public void OnDisconnect()
{
AddToInformation("Calling Disconnect");
GoogleSignIn.DefaultInstance.Disconnect();
}
internal void OnAuthenticationFinished(Task<GoogleSignInUser> task)
{
if (task.IsFaulted)
{
using (IEnumerator<Exception> enumerator = task.Exception.InnerExceptions.GetEnumerator())
{
if (enumerator.MoveNext())
{
GoogleSignIn.SignInException error = (GoogleSignIn.SignInException)enumerator.Current;
AddToInformation("Got Error: " + error.Status + " " + error.Message);
}
else
{
AddToInformation("Got Unexpected Exception?!?" + task.Exception);
}
}
}
else if (task.IsCanceled)
{
AddToInformation("Canceled");
}
else
{
AddToInformation("Welcome: " + task.Result.DisplayName + "!");
AddToInformation("Email = " + task.Result.Email);
AddToInformation("Google ID Token = " + task.Result.IdToken);
AddToInformation("Email = " + task.Result.Email);
SignInWithGoogleOnFirebase(task.Result.IdToken, task.Result.UserId);
}
}
private void SignInWithGoogleOnFirebase(string idToken, string UID) (Player.instance.setGoogleUID(UID))
{
Credential credential = GoogleAuthProvider.GetCredential(idToken, null);
auth.SignInWithCredentialAsync(credential).ContinueWith(task =>
{
AggregateException ex = task.Exception;
if (ex != null)
{
if (ex.InnerExceptions[0] is FirebaseException inner && (inner.ErrorCode != 0)) ;
AddToInformation("\nError code = " + inner.ErrorCode + " Message = " + inner.Message);
}
else
{
AddToInformation("Sign In Successful., UID: " + UID);
mainCanvas.GoInGame();
Player.instance.SetIsSignIn(true);
Player.instance.setGoogleUID(UID);
AddToInformation("Success2");
StartCoroutine(signInSetPlayer());
}
});
}
public void OnSignInSilently()
{
GoogleSignIn.Configuration = configuration;
GoogleSignIn.Configuration.UseGameSignIn = false;
GoogleSignIn.Configuration.RequestIdToken = true;
AddToInformation("Calling SignIn Silently");
GoogleSignIn.DefaultInstance.SignInSilently().ContinueWith(OnAuthenticationFinished);
}
public void OnGamesSignIn()
{
GoogleSignIn.Configuration = configuration;
GoogleSignIn.Configuration.UseGameSignIn = true;
GoogleSignIn.Configuration.RequestIdToken = false;
AddToInformation("Calling Games SignIn");
GoogleSignIn.DefaultInstance.SignIn().ContinueWith(OnAuthenticationFinished);
}
private void AddToInformation(string str) { infoText.text += "\n" + str; }
Is there a way to get rid of practise.AcademicProgram in the output when the display() is called for an object initialized by the parameterized constructor. In my code below this occurs when s2.Display(); is executed.
Below is my working code for the same:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace practise
{
public class AcademicProgram
{
//Memnber variables
private int programCode;
private string programName;
private int programCredits;
//Properties for reading and writting the values of private fields
public int ProgramCode { get => programCode; set => programCode = value; }
public string ProgramName { get => programName; set => programName = value; }
public int ProgramCredits { get => programCredits; set => programCredits = value; }
//Default Constructor
public AcademicProgram()
{
}
//Parameterized Constructor
public AcademicProgram (int programCode, string programName, int programCredits)
{
this.programCode = programCode;
this.programName = programName;
this.programCredits = programCredits;
}
public void DisplayResults()
{
Console.WriteLine("Program Code: {0}\nProgram Name: {1}\nProgram Credits: {2}\n", programCode, programName, programCredits);
Console.WriteLine();
}
}
public class Instructor
{
//Member variables
public string forename;
public string surname;
public int identificationNumber;
public AcademicProgram academicProgram;
//Default Constructor
public Instructor()
{
this.forename = string.Empty;
this.surname = string.Empty;
this.identificationNumber = 0;
this.academicProgram = null;
}
//Parameterized Constructor
public Instructor(string forename, string surname, int identificationNumber, AcademicProgram academicProgram)
{
this.forename = forename;
this.surname = surname;
this.identificationNumber = identificationNumber;
this.academicProgram = academicProgram;
}
// Member Function to display values of member variables on Console.
public void Display()
{
Console.WriteLine(this.forename + ", " + this.surname + ", " + this.identificationNumber + ", " + this.academicProgram);
Console.WriteLine();
}
//Driver function
static void Main(string[] args)
{
//Instantiating object to call non-static member method
Instructor p = new Instructor();
p.Go();
Console.ReadKey();
}
//Non-static Member function
public void Go()
{
//Instantiating object without passing any values on runtime.
Instructor s = new Instructor();
//Instantiating object of AcademicProgram class without passing any values on runtime.
AcademicProgram progName = new AcademicProgram ();
//Set the values of fields using properties
progName.ProgramCode = 8230;
progName.ProgramName = "Systems Development: Cocnepts and Analysis";
progName.ProgramCredits = 4;
// Instantiating object while providing values on runtime.
Instructor s2 = new Instructor("Eddie ", "Jessup", 2394589, progName);
//Call to display method
s.Display();
s2.Display();
progName.DisplayResults();
}
}
}
Which gives an output shown here
Aside from override ToString(), I was able to fix it by a simple fix in display() of Instructor class as below:
public void Display()
{
Console.WriteLine(this.forename + ", " + this.surname + ", " + this.identificationNumber + ", " + this.academicProgram.ProgramCode + ", " + this.academicProgram.ProgramName + ", " + this.academicProgram.ProgramCredits);
Console.WriteLine();
}
I'm setting up my architechture to use Cef.Offscreen. In order to make it easy to work with I have divided some parts. But I run into a problem that controller loading finshes and serves a view before everything has been able to load.
Here's my structure --> Controller
public ActionResult InitBrowser()
{
ICefSharpRenderer renderer = RendererSingelton.GetInstance();
//Try to render something in default appdomain
renderer.LoginToTradingView(null, null);
ViewBag.SiteTitle = BrowserActions.RunScriptInNamedBrowser("loginbrowser", #"(function() {return document.title;} )();");
ViewBag.ImagesixtyfourUrl = BrowserActions.TakeScreenshot("loginbrowser");
//this is returned to fast, we have to wait for all
return View();
}
I have this class to get do some basic actions and initialize if needed.
public class CefSharpRenderer : MarshalByRefObject, ICefSharpRenderer
{
private ChromiumWebBrowser _browser;
private TaskCompletionSource<JavascriptResponse> _taskCompletionSource;
private string _name;
public void LoginToTradingView(string url, string browserName)
{
CheckIfCefIsInitialized();
BrowserFactory.GetBrowserInstance(#"https://se.tradingview.com/", "loginbrowser");
}
public void CreateBrowserAndGoToUrl(string url, string browserName)
{
CheckIfCefIsInitialized();
BrowserFactory.GetBrowserInstance(url, "browserName");
}
public void CheckIfCefIsInitialized()
{
if (!Cef.IsInitialized)
{
var settings = new CefSettings();
var assemblyPath = Path.GetDirectoryName(new Uri(GetType().Assembly.CodeBase).LocalPath);
settings.BrowserSubprocessPath = Path.Combine(assemblyPath, "CefSharp.BrowserSubprocess.exe");
settings.ResourcesDirPath = assemblyPath;
settings.LocalesDirPath = Path.Combine(assemblyPath, "locales");
var osVersion = Environment.OSVersion;
//Disable GPU for Windows 7
if (osVersion.Version.Major == 6 && osVersion.Version.Minor == 1)
{
// Disable GPU in WPF and Offscreen examples until #1634 has been resolved
settings.CefCommandLineArgs.Add("disable-gpu", "1");
}
//Perform dependency check to make sure all relevant resources are in our output directory.
Cef.Initialize(settings, performDependencyCheck: false, cefApp: null);
}
}
}
I get my browserinstance here and connected the events to be fired.
public static class BrowserFactory
{
public static ChromiumWebBrowser GetBrowserInstance(string _url, string browsername)
{
if (!BrowserContainer.CheckIfBrowserExists(browsername))
{
ChromiumWebBrowser _browser = new ChromiumWebBrowser(_url);
_browser.LoadingStateChanged += BrowserEvents.OnLoadingStateChanged;
BrowserContainer.AddDataHolder(browsername, new DataBrowserHolder { BrowserName = browsername, ChromiumWebBrow = _browser });
return _browser;
}
return null;
}
}
Browserevent loads correct page.
public static class BrowserEvents
{
public static void OnLoadingStateChanged(object sender, LoadingStateChangedEventArgs args)
{
if (args.IsLoading == false)
{
ChromiumWebBrowser cwb = (ChromiumWebBrowser)sender;
if (cwb.Address == "https://se.tradingview.com/")
{
BrowserActions.LogInToTradingView("xxxxx", "yyyyyyy", "loginbrowser");
}
}
}
}
Last my browseractions, spare med for the thread sleeps it's just under construction and it works atm.
public static class BrowserActions
{
public static void LogInToTradingView(string twusername, string twpassword, string browserName)
{
ChromiumWebBrowser _dataholder = BrowserContainer.GetDataHolderByName(browserName).ChromiumWebBrow;
IFrame ifww = _dataholder.GetMainFrame();
// var lull = #"(function() { var serielength = TradingView.bottomWidgetBar._widgets.backtesting._reportWidgetsSet.reportWidget._data.filledOrders.length; return serielength; })();";
// JavascriptResponse _js = Task.Run(async () => { return await _browser.GetMainFrame().EvaluateScriptAsync(lull); }).Result;
ifww.ExecuteJavaScriptAsync(#"(function() { window.document.getElementsByClassName('tv-header__link tv-header__link--signin js-header__signin')[0].click();})();");
// var loginusernamescript =
var loginpasswordscript = #"(function() { window.document.getElementsByClassName('tv-control-material-input tv-signin-dialog__input tv-control-material-input__control')[1].value= " + twpassword + "; })();";
var clkloginbtn = #"(function() { document.getElementsByClassName('tv-button tv-button--no-border-radius tv-button--size_large tv-button--primary_ghost tv-button--loader')[0].click();})();";
Thread.Sleep(300);
ifww.ExecuteJavaScriptAsync(#"(function() { window.document.getElementsByClassName('tv-control-material-input tv-signin-dialog__input tv-control-material-input__control')[0].click();})();");
Thread.Sleep(50);
ifww.ExecuteJavaScriptAsync(#"(function() { window.document.getElementsByClassName('tv-control-material-input tv-signin-dialog__input tv-control-material-input__control')[0].value = '" + twusername + "';})();");
Thread.Sleep(50);
ifww.ExecuteJavaScriptAsync(#"(function() { window.document.getElementsByClassName('tv-control-material-input tv-signin-dialog__input tv-control-material-input__control')[1].click();})();");
Thread.Sleep(50);
ifww.ExecuteJavaScriptAsync(#"(function() { window.document.getElementsByClassName('tv-control-material-input tv-signin-dialog__input tv-control-material-input__control')[1].value = '" + twpassword + "';})();");
Thread.Sleep(50);
ifww.ExecuteJavaScriptAsync(#"(function() { document.getElementsByClassName('tv-button tv-button--no-border-radius tv-button--size_large tv-button--primary_ghost tv-button--loader')[0].click();})();");
}
public static string TakeScreenshot(string browserName)
{
try
{
Bitmap img = Task.Run(async () => { return await BrowserContainer.GetDataHolderByName(browserName).ChromiumWebBrow.ScreenshotAsync(); }).Result;
// object mgss = img.Clone();
string baseen = ExtraFunctions.ToBase64String(img, ImageFormat.Png);
return baseen;
}
catch (Exception e)
{
var x = e.InnerException;
return null;
}
}
public static string RunScriptInNamedBrowser(string browserName, string script)
{
try
{
string str = Task.Run(async () => { return await BrowserContainer.GetDataHolderByName(browserName).ChromiumWebBrow.GetMainFrame().EvaluateScriptAsync(script); }).Result.ToString();
// object mgss = img.Clone();
return str;
}
catch (Exception e)
{
var x = e.InnerException;
return null;
}
}
}
How can I get my browser actions to report back to my controller so that I can wait for them to finish?
For a Task asynchronous operation to report back, it's possible to use Progress<T>. How that's done is detailed in Enabling Progress and Cancellation in Async APIs. The key is:
var progressIndicator = new Progress<int>(ReportProgress);
This creates a Progress<T> object that can indicate how far a task is complete, and also call a custom method (ReportProgress) at set intervals. You can create a custom class if necessary instead of using int.
So your browser actions can report back to the controller with the progress reporting method until everything is complete.
I am programming a discord bot in Discord .NET 0.9 and I get a stack overflow error when I try to run it. The problem a occurs when I make a instance of my Program.cs in my Functions.cs
My Program.cs:
using System;
using System.Linq;
using Discord;
using Discord.Commands;
using System.IO;
using fatobg;
namespace fatobg
{
class Program
{
CommandManager cm = new CommandManager();
public static Program _instance = new Program();
static void Main(string[] args)
{
new Program().Start();
}
public DiscordClient _client;
public void Start()
{
Console.Title = "Matchmaking Discord BOT";
_client = new DiscordClient(x =>
{
x.AppName = "Gerry";
x.AppUrl = "www.google.com";
x.LogLevel = LogSeverity.Info;
x.LogHandler = Log;
});
_client.UsingCommands(x =>
{
x.PrefixChar = '?';
x.AllowMentionPrefix = true;
x.HelpMode = HelpMode.Public;
});
var token = "Changed";
cm.Commands(_client);
onJoin();
_client.ExecuteAndWait(async () =>
{
await _client.Connect(token, TokenType.Bot);
setGame(_client, "?help");
});
}
public void setGame(DiscordClient _client, string game)
{
_client.SetGame(game);
}
public void onJoin()
{
_client.UserJoined += async (s, e) =>
{
await e.Server.GetChannel(318558393759694849).SendMessage($":loudspeaker: | Everyone welcome {e.User.Mention} to the server!");
};
}
public void Log(Object sender, LogMessageEventArgs e)
{
Console.WriteLine($"[{e.Severity}] [{e.Source}] {e.Message}");
}
}
}
My CommandManager.cs:
using System;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Threading.Tasks;
using Discord;
using System.Net.Http;
using Discord.Commands;
using System.Text.RegularExpressions;
using System.Xml.Serialization;
using System.IO;
using System.Threading;
using MySql.Data;
using MySql.Data.MySqlClient;
namespace fatobg
{
class CommandManager
{
public static CommandManager _instance = new CommandManager();
Functions function = new Functions();
public void Commands(DiscordClient _client)
{
var cService = _client.GetService<CommandService>();
cService.CreateCommand("say")
.Description("returns commands")
.Parameter("message", ParameterType.Unparsed)
.Do(async (e) =>
{
Message[] messageToDelete;
int deleteNumber = 1;
messageToDelete = await e.Channel.DownloadMessages(deleteNumber);
await e.Channel.DeleteMessages(messageToDelete);
var toReturn = $":envelope: | {e.GetArg("message")}";
await e.Channel.SendMessage(toReturn);
Console.WriteLine(toReturn);
});
cService.CreateCommand("updatedb")
.Description("updates database")
.Do(async (e) =>
{
Message[] messageToDelete; //deletes command
int deleteNumber = 1;
messageToDelete = await e.Channel.DownloadMessages(deleteNumber);
await e.Channel.DeleteMessages(messageToDelete);
try
{
if (e.User.ServerPermissions.Administrator)
{
foreach (User user in e.Server.Users)
{
if(!user.IsBot)
function.UpdateDB(user);
}
var toReturn = $":white_check_mark: | Done updateing the database. {e.User.Mention}";
await e.Channel.SendMessage(toReturn);
Console.WriteLine(toReturn);
}
else
{
var toReturn = $":exclamation: | Get out of here {e.User.Mention} you have no power over me!";
await e.Channel.SendMessage(toReturn);
Console.WriteLine(toReturn);
}
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex);
}
});
cService.CreateCommand("duo")
.Description("returns commands")
.Do(async (e) =>
{
Message[] messageToDelete;
int deleteNumber = 1;
messageToDelete = await e.Channel.DownloadMessages(deleteNumber);
await e.Channel.DeleteMessages(messageToDelete);
});
cService.CreateCommand("yamikage")
.Description("Animated gingy")
.Do(async (e) =>
{
Message[] messageToDelete;
int deleteNumber = 1;
messageToDelete = await e.Channel.DownloadMessages(deleteNumber);
await e.Channel.DeleteMessages(messageToDelete);
await e.Channel.SendFile("Gifs/gingy.gif");
Console.WriteLine("Send epic gingy meme");
});
}
}
}
My Functions.cs:
using Discord;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace fatobg
{
class Functions
{
Program main = new Program();
public void UpdateDB(User user)
{
if (File.Exists(#"D:\Databases\DiscordUsers\" + user.Id + ".duser"))
{
System.IO.File.Delete(#"D:\Databases\DiscordUsers\" + user.Id + ".duser");
string[] Data = { user.Name, Roles(user) };
System.IO.File.WriteAllLines(#"D:\Databases\DiscordUsers\" + user.Id + ".duser", Data);
}
else
{
string[] Data = { user.Name, Roles(user) };
System.IO.File.WriteAllLines(#"D:\Databases\DiscordUsers\" + user.Id + ".duser", Data);
}
}
public string Roles(User user)
{
string toreturn = string.Empty;
foreach (Role role in user.Roles)
{
if (role.Name!="Admin"||role.Name!="Mod"||role.Name!="#everyone")
{
toreturn += role.Name + "|";
}
}
return toreturn;
}
public string GetUsername(string uid)
{
if (File.Exists(#"D:\Databases\DiscordUsers\" + uid + ".duser"))
{
string[] Data = File.ReadAllLines(#"D:\Databases\DiscordUsers\" + uid + ".duser");
return Data[0];
}
else
{
return null;
}
}
public void AddToQueue(User user)
{
List<User> NA = new List<User>();
List<User> EU = new List<User>();
List<User> OC = new List<User>();
List<User> AS = new List<User>();
List<User> SA = new List<User>();
Server server = main._client.FindServers("Find A Team On Battlegrounds (Bot Testing)").FirstOrDefault();
User usr = server.FindUsers(user.Name).FirstOrDefault();
if (File.Exists(#"D:\Databases\Duo.queue"))
{
string[] UData = System.IO.File.ReadAllLines(#"D:\Databases\Duo.queue");
System.IO.File.Delete(#"D:\Databases\Duo.queue");
foreach(String uid in UData)
{
User tempuser = user.Server.FindUsers(GetUsername(uid)).FirstOrDefault();
List<Role> roles = tempuser.Roles.ToList();
foreach(Role role in roles)
{
if (role.Name == "[NA]")
NA.Add(tempuser);
else if (role.Name == "[EU]")
EU.Add(tempuser);
else if (role.Name == "[OC]")
OC.Add(tempuser);
else if (role.Name == "[AS]")
AS.Add(tempuser);
else if (role.Name == "[SA]")
SA.Add(tempuser);
}
}
List<Role> uroles = usr.Roles.ToList();
foreach (Role role in uroles)
{
if (role.Name == "[NA]")
NA.Add(usr);
else if (role.Name == "[EU]")
EU.Add(usr);
else if (role.Name == "[OC]")
OC.Add(usr);
else if (role.Name == "[AS]")
AS.Add(usr);
else if (role.Name == "[SA]")
SA.Add(usr);
}
File.WriteAllLines(#"D:\Databases\Duo.queue", UData);
File.AppendAllText(#"D:\Databases\Duo.queue", usr.Id.ToString() + Environment.NewLine);
if (NA.Count == 2)
{
server.GetChannel(319281246746312714).SendMessage($":exclamation: | A new team has been found for NA servers. {NA[0].Mention} and {NA[1].Mention} prepare to fight.");
string[] Data = System.IO.File.ReadAllLines(#"D:\Databases\Duo.queue");
System.IO.File.Delete(#"D:\Databases\Duo.queue");
foreach (String id in Data)
{
if(id!=NA[0].Id.ToString()&&id!=NA[1].Id.ToString())
File.AppendAllText(#"D:\Databases\Duo.queue", id + Environment.NewLine);
}
NA.Clear();
}
else if (EU.Count == 2){
server.GetChannel(319281246746312714).SendMessage($":exclamation: | A new team has been found for EU servers. {EU[0].Mention} and {EU[1].Mention} prepare to fight.");
string[] Data = System.IO.File.ReadAllLines(#"D:\Databases\Duo.queue");
System.IO.File.Delete(#"D:\Databases\Duo.queue");
foreach (String id in Data)
{
if (id!=EU[0].Id.ToString()&&id!=EU[1].Id.ToString())
File.AppendAllText(#"D:\Databases\Duo.queue", id + Environment.NewLine);
}
EU.Clear();
}
else if (OC.Count == 2)
{
server.GetChannel(319281246746312714).SendMessage($":exclamation: | A new team has been found for OC servers. {OC[0].Mention} and {OC[1].Mention} prepare to fight.");
string[] Data = System.IO.File.ReadAllLines(#"D:\Databases\Duo.queue");
System.IO.File.Delete(#"D:\Databases\Duo.queue");
foreach (String id in Data)
{
if (id!=OC[0].Id.ToString()&&id!=OC[1].Id.ToString())
File.AppendAllText(#"D:\Databases\Duo.queue", id + Environment.NewLine);
}
OC.Clear();
}
else if (AS.Count == 2)
{
server.GetChannel(319281246746312714).SendMessage($":exclamation: | A new team has been found for AS servers. {AS[0].Mention} and {AS[1].Mention} prepare to fight.");
string[] Data = System.IO.File.ReadAllLines(#"D:\Databases\Duo.queue");
System.IO.File.Delete(#"D:\Databases\Duo.queue");
foreach (String id in Data)
{
if (id != AS[0].Id.ToString() && id != AS[1].Id.ToString())
File.AppendAllText(#"D:\Databases\Duo.queue", id + Environment.NewLine);
}
AS.Clear();
}
else if (SA.Count == 2)
{
server.GetChannel(319281246746312714).SendMessage($":exclamation: | A new team has been found for SA servers. {SA[0].Mention} and {SA[1].Mention} prepare to fight.");
string[] Data = System.IO.File.ReadAllLines(#"D:\Databases\Duo.queue");
System.IO.File.Delete(#"D:\Databases\Duo.queue");
foreach (String id in Data)
{
if (id != SA[0].Id.ToString()&&id!=SA[1].Id.ToString())
File.AppendAllText(#"D:\Databases\Duo.queue", id + Environment.NewLine);
}
SA.Clear();
}
}
else
{
File.AppendAllText(#"D:\Databases\Duo.queue", usr.Id.ToString() + Environment.NewLine);
}
}
}
}
This is what happens:
Instantiate Program;
Program instantiates CommandManager;
CommandManager instantiates Functions;
Functions instantiates Program;
Return to 1.
What you should do:
Pass along an instance of Program to CommandManager and Functions. In that way, you have no circular reference any more.
For example your Functions class should start with this:
class Functions
{
Program main;
public Functions(Program p)
{
this.main = p;
}
And your CommandManager:
class CommandManager
{
Program main;
Functions function;
public CommandManager(Program p)
{
this.main = p;
this.function = new Function(p);
}
I'm just trying to do a simple event handler on a string variable, so that if the string changes, it will do a Console.WriteLine (using the new Reactive library from MS (Rx))
The issue that I have is that it will display the first bit when I instantiate the class ("RandomGuid : Mine?"), but after that, none of the stuff I change afterwards spits anything out to the console.
I went through the HOL from the MS website, but it goes straight from defining the Observable into reading values from a textbox, when all I want to do is watch whether a string was changed.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MynahBirds
{
class Program
{
static void Main(string[] args)
{
List<Minah> minahs = new List<Minah>();
for (int i = 0; i < 10; i++) {
minahs.Add(new Minah());
}
foreach (var item in minahs) {
item.peers = minahs;
}
minahs.ForEach(m => m.s = Observable.Return<string>("Mine"));
minahs.ForEach(m => m.s = Observable.Return<string>("Whee"));
minahs.ForEach(m => m.s = Observable.Return<string>("Argh"));
Console.ReadLine();
}
}
class Minah
{
Guid Id;
public List<Minah> peers;
IDisposable subscription;
public IObservable<string> s = Observable.Return<string>("Mine?");
public Minah()
{
try {
this.Id = Guid.NewGuid();
subscription = s.Subscribe((string a) => {
Console.WriteLine("{0} : {1}", this.Id, a);
},
(Exception ex) => {
Console.WriteLine("Error {0} hit", ex.ToString());
},
() => { });
} catch (Exception ex) {
Console.WriteLine(ex.ToString());
Console.ReadLine();
throw;
}
}
}
}
When you assign to m.s in the ForEach you are not updating the existing observable (which you have subscribed to) with a new value, instead you are creating new observables, which is what Observable.Return does. The code below does what I think you expect:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MynahBirds
{
class Program
{
static void Main(string[] args)
{
List<Minah> minahs = new List<Minah>();
for (int i = 0; i < 10; i++)
{
minahs.Add(new Minah());
}
foreach (var item in minahs)
{
item.peers = minahs;
}
minahs.ForEach(m => m.s.OnNext("Mine"));
minahs.ForEach(m => m.s.OnNext("Whee"));
minahs.ForEach(m => m.s.OnNext("Argh"));
Console.ReadLine();
}
}
class Minah
{
Guid Id;
public List<Minah> peers;
IDisposable subscription;
public ISubject<string> s = new Subject<string>();
public Minah()
{
try
{
this.Id = Guid.NewGuid();
subscription = s.Subscribe((string a) =>
{
Console.WriteLine("{0} : {1}", this.Id, a);
},
(Exception ex) =>
{
Console.WriteLine("Error {0} hit", ex.ToString());
},
() => { });
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
Console.ReadLine();
throw;
}
}
}
}
Instead of using Observable.Return<T>(), here I use a Subject, which is both an observer and an observable sequence. It updates all its subscriptions with each value it observes. So when OnNext is called on the subject, it is forwarded to all subscriptions.
If you need the initial value (Mine?) you can add s.OnNext("Mine?"); at the end of the Minah constructor.
using System;
using System.Collections.Generic;
using System.Threading;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Collections.Concurrent;
namespace MynahBirds
{
class Program
{
static void Main(string[] args)
{
ThreadPool.SetMaxThreads(100, 100);
ConcurrentBag<Minah> minahs = new ConcurrentBag<Minah>();
Stopwatch ti = new Stopwatch();
ti.Start();
Task.Factory.StartNew(() => {
for (int i = 1; i < 2501; i++) {
minahs.Add(new Minah(i));
};
});
Task.Factory.StartNew(() => {
for (int i = 1; i < 2501; i++) {
minahs.Add(new Minah(i));
};
});
Task.Factory.StartNew(() => {
for (int i = 1; i < 2501; i++) {
minahs.Add(new Minah(i));
};
});
Task.Factory.StartNew(() => {
for (int i = 1; i < 2501; i++) {
minahs.Add(new Minah(i));
};
});
Task.WaitAll();
string[] alpha = { "Alpha", "Bravo", "Charlie", "Delta", "Eagle", "Foxtrot", "Gulf", "Hotel" };
foreach (string s in alpha) {
Console.WriteLine(s);
Task.Factory.StartNew(() => minahs.AsParallel().ForAll(m => m.RepeatWord = s)).Wait();
}
minahs.AsParallel().ForAll(m => m.s.OnCompleted());
ti.Stop();
Console.WriteLine("{1} birds : {0} seconds", ti.Elapsed.TotalSeconds, minahs.Count);
Console.ReadLine();
}
}
class Minah
{
Guid Id;
IDisposable subscription;
public ISubject<string> s = new Subject<string>();
private string _RepeatWord;
public string RepeatWord
{
get
{
return _RepeatWord;
}
set
{
this.s.OnNext(value);
_RepeatWord = value;
}
}
public Minah(int i)
{
try {
this.Id = Guid.NewGuid();
subscription = s.Subscribe((string a) => {
Console.WriteLine("{0} : {1}", i, a);
},
(Exception ex) => {
Console.WriteLine("Error {0} hit", ex.ToString());
},
() => { /* Console.WriteLine("{0} : Completed", this.Id); */ });
} catch (Exception ex) {
Console.WriteLine(ex.ToString());
Console.ReadLine();
throw;
}
}
}
}
This is what I ended up doing with help from Markus. More playing around with parallelism. Interestingly, if I remove the .Wait() from the end of the .ForAll(... RepeatWord = s), it will only do the last word in the sequence. I'm guessing that is a closure thing, but I'm not overly concerned about it.