public void ConnectionManagerAddsNewServicesFromServiceDiscovery() { var manualResetEvent = new System.Threading.ManualResetEvent(false); var serviceUri1 = new ServiceUri() { Address = "1" }; var serviceUri2 = new ServiceUri() { Address = "2" }; Dictionary<ServiceUri, PerformanceStatistics> services = new Dictionary<ServiceUri, PerformanceStatistics>() { {serviceUri1, new PerformanceStatistics()}, {serviceUri2, new PerformanceStatistics()} }; var serviceDiscoveryMock = new Mock<IServiceDiscovery>(MockBehavior.Strict); serviceDiscoveryMock.Setup(sd => sd.GetPerformanceStatistics()).Returns(() => services).Callback(() => manualResetEvent.Set()); var manager = new ConnectionManager(remoteService: null, listener: null, serviceDiscovery: serviceDiscoveryMock.Object, serviceDiscoveryPeriod: new TimeSpan(days: 0, hours: 0, minutes: 0, seconds: 0, milliseconds: 10)); manualResetEvent.WaitOne(); manager.RemoteServices.Count().ShouldBe(2); services.Add(new ServiceUri(), new PerformanceStatistics()); manualResetEvent.Reset(); manualResetEvent.WaitOne(); manager.RemoteServices.Count().ShouldBe(3); }
public void CoordinatorWorks() { //Bluepath.Log.ClearXes(); using (var redisStorage = new RedisStorage(Host)) { this.storage = new BluepathStorage(redisStorage); this.storage.Clean(); this.storage.Store("f1", "ala ma kota"); this.storage.Store("f2", "kota alama"); this.storage.Store("f3", "dolan ma"); var filesToRead = this.storage.ListFiles(); var mapperCodeFile = new FileUri("file:///SampleMapper.cs"); var reducerCodeFile = new FileUri("file:///SampleReducer.cs"); TestHelpers.LoadToStorage(@"..\..\SampleMapper.cs", mapperCodeFile, this.storage); TestHelpers.LoadToStorage(@"..\..\SampleReducer.cs", reducerCodeFile, this.storage); var connectionManager = new ConnectionManager(new Dictionary<ServiceUri, PerformanceStatistics>(), null, null, null); var scheduler = new ThreadNumberScheduler(connectionManager); var coordinator = new Coordinator(connectionManager, scheduler, DistributedThread.ExecutorSelectionMode.LocalOnly); coordinator.Start(2, 2, mapperCodeFile, reducerCodeFile, filesToRead.Select(f => new FileUri(f.ToString()))); string result = string.Empty; Debug.WriteLine("Listing files..."); foreach (var file in this.storage.ListFiles()) { var fileName = this.storage.GetFileName(file); Debug.Write(fileName); try { Debug.WriteLine(" -- {0}", (object)Base64Decode(fileName)); } catch { Debug.WriteLine(string.Empty); } } foreach (var uri in this.storage.ListFiles()) { var file = this.storage.GetFileName(uri); if (file.Contains("REDUCE") && file.Contains("kota")) { result = this.storage.Read(file); Debug.WriteLine("File '{0}' contains '{1}'.", file, result); } } result.ShouldBe("2"); this.storage.Clean(); } System.Threading.Thread.Sleep(3000); //Bluepath.Log.SaveXes(@"c:\temp\bluepath.xes", clearListAfterSave: true); //Bluepath.Log.ClearXes(); }
public void ConnectionManagerHandlesNullDictionaryInConstructor() { Dictionary<ServiceUri, PerformanceStatistics> services = null; var manager = new ConnectionManager(services, null); manager.RemoteServices.ShouldBeEmpty(); }
private static void RunTest(ConnectionManager connectionManager, ThreadNumberScheduler scheduler, Options options) { var numberOfElements = options.NoOfElements; var numberOfShards = options.NoOfShards; var threads = new List<DistributedThread>(); Log.TraceMessage(Log.Activity.Custom, "Running test"); var sw = new Stopwatch(); sw.Start(); var processFunc = new Func<int, long>( (amount) => { var r = new Random(); long result = 0; for (int j = 0; j < amount; j++) { var x = r.NextDouble(); var y = r.NextDouble(); if (x * x + y * y < 1.0) { result++; } } return result; }); for (int i = 0; i < numberOfShards; i++) { var thread = DistributedThread.Create( processFunc, connectionManager, scheduler ); thread.Start(numberOfElements); threads.Add(thread); } long sum = 0; foreach (var thread in threads) { thread.Join(); if (thread.State == Executor.ExecutorState.Faulted) { Console.WriteLine("Err"); } else { sum += (long)thread.Result; } } var pi = 4.0 * sum / (numberOfElements * numberOfShards); sw.Stop(); Console.WriteLine(string.Format("PI: {0}", pi)); Console.WriteLine(sw.ElapsedMilliseconds); }
static void Main(string[] args) { var options = new Options(); if (CommandLine.Parser.Default.ParseArguments(args, options)) { Bluepath.Log.DistributedMemoryHost = options.RedisHost; Bluepath.Log.WriteInfoToConsole = false; var bluepathListener = new BluepathListener(options.Ip, options.Port); using (var serviceDiscoveryClient = new CentralizedDiscovery.Client.CentralizedDiscovery( new ServiceUri(options.CentralizedDiscoveryURI, BindingType.BasicHttpBinding), bluepathListener ) ) { using (var connectionManager = new ConnectionManager( remoteService: null, listener: bluepathListener, serviceDiscovery: serviceDiscoveryClient, serviceDiscoveryPeriod: TimeSpan.FromSeconds(30))) { System.Threading.Thread.Sleep(1500); var scheduler = new ThreadNumberScheduler(connectionManager); if (options.IsSlave == 0) { Log.TraceMessage(Log.Activity.Custom, "Running master"); //RunRedisTest(options); RunTest(connectionManager, scheduler, options); } else { Log.TraceMessage(Log.Activity.Custom, "Running slave"); } Console.WriteLine("Press <Enter> to stop the service."); Console.ReadLine(); } } } }
public void ConnectionManagerAddsNewServicesFromRemoteServiceDiscovery() { var serviceDiscoveryHost = new CentralizedDiscovery.CentralizedDiscoveryListener("localhost", 30000); var bluepathListener1 = new Bluepath.Services.BluepathListener("localhost", 30001); var bluepathListener2 = new Bluepath.Services.BluepathListener("localhost", 30002); var bluepathListener3 = new Bluepath.Services.BluepathListener("localhost", 30003); try { using (var serviceDiscoveryClient1 = new CentralizedDiscovery.Client.CentralizedDiscovery(serviceDiscoveryHost.MasterUri, bluepathListener1)) { using (var serviceDiscoveryClient2 = new CentralizedDiscovery.Client.CentralizedDiscovery(serviceDiscoveryHost.MasterUri, bluepathListener2)) { var connectionManager = new Bluepath.Services.ConnectionManager(remoteService: null, listener: bluepathListener1, serviceDiscovery: serviceDiscoveryClient1, serviceDiscoveryPeriod: new TimeSpan(days: 0, hours: 0, minutes: 0, seconds: 0, milliseconds: 100)); TestHelpers.RepeatUntilTrue(() => connectionManager.RemoteServices.Count() == 1, times: 10); connectionManager.RemoteServices.Count().ShouldBe(1); using (var serviceDiscoveryClient3 = new CentralizedDiscovery.Client.CentralizedDiscovery(serviceDiscoveryHost.MasterUri, bluepathListener3)) { TestHelpers.RepeatUntilTrue(() => connectionManager.RemoteServices.Count() == 2, times: 10); connectionManager.RemoteServices.Count().ShouldBe(2); } } } } finally { serviceDiscoveryHost.Stop(); bluepathListener1.Stop(); bluepathListener2.Stop(); bluepathListener3.Stop(); } }
public void CentralizedDiscoveryProvidesInformationAboutLoadOfTheNodes() { var serviceDiscoveryHost = new CentralizedDiscovery.CentralizedDiscoveryListener("localhost", 41000); var bluepathListener1 = new Bluepath.Services.BluepathListener("localhost", 41001); var bluepathListener2 = new Bluepath.Services.BluepathListener("localhost", 41002); try { using (var serviceDiscoveryClient1 = new CentralizedDiscovery.Client.CentralizedDiscovery(serviceDiscoveryHost.MasterUri, bluepathListener1)) { using (var serviceDiscoveryClient2 = new CentralizedDiscovery.Client.CentralizedDiscovery(serviceDiscoveryHost.MasterUri, bluepathListener2)) { var connectionManager = new Bluepath.Services.ConnectionManager( remoteService: null, listener: bluepathListener1, serviceDiscovery: serviceDiscoveryClient1); var scheduler = new ThreadNumberScheduler(connectionManager); TestHelpers.RepeatUntilTrue(() => connectionManager.RemoteServices.Count() == 1, times: 10); connectionManager.RemoteServices.Count().ShouldBe(1); // TODO: Review this test var testMethod = new Func<int, int, int>( (a, b) => { Thread.Sleep(100); return a + b; }); var thread = DistributedThread.Create( testMethod, connectionManager, scheduler, DistributedThread.ExecutorSelectionMode.RemoteOnly ); thread.Start(4, 5); var performanceStatistics = serviceDiscoveryClient1.GetPerformanceStatistics(); performanceStatistics.Count.ShouldBe(2); performanceStatistics.ElementAt(0).Key.Address.ShouldNotBeSameAs(performanceStatistics.ElementAt(1).Key.Address); performanceStatistics.ElementAt(0).Value.NumberOfTasks[ExecutorState.NotStarted].ShouldBe(0); performanceStatistics.ElementAt(0).Value.NumberOfTasks[ExecutorState.Running].ShouldBeLessThanOrEqualTo(1); performanceStatistics.ElementAt(1).Value.NumberOfTasks[ExecutorState.Running].ShouldBeLessThanOrEqualTo(1); if (performanceStatistics.ElementAt(0).Value.NumberOfTasks[ExecutorState.Running] > 0 && performanceStatistics.ElementAt(1).Value.NumberOfTasks[ExecutorState.Running] > 0) { Assert.Fail("One task was scheduled but two are reported to be running."); } (performanceStatistics.ElementAt(0).Value.NumberOfTasks[ExecutorState.Running] + performanceStatistics.ElementAt(1).Value.NumberOfTasks[ExecutorState.Running]).ShouldBe(1); performanceStatistics.ElementAt(0).Value.NumberOfTasks[ExecutorState.Finished].ShouldBe(0); performanceStatistics.ElementAt(0).Value.NumberOfTasks[ExecutorState.Faulted].ShouldBe(0); thread.Join(); } } } finally { serviceDiscoveryHost.Stop(); bluepathListener1.Stop(); bluepathListener2.Stop(); } }
public void ConnectionManagerFetchesServicesFromRemoteServiceDiscovery() { var serviceDiscoveryHost = new CentralizedDiscovery.CentralizedDiscoveryListener("localhost", 20000); var bluepathListener1 = new Bluepath.Services.BluepathListener("localhost", 20001); var bluepathListener2 = new Bluepath.Services.BluepathListener("localhost", 20002); try { using (var serviceDiscoveryClient1 = new CentralizedDiscovery.Client.CentralizedDiscovery(serviceDiscoveryHost.MasterUri, bluepathListener1)) { using (var serviceDiscoveryClient2 = new CentralizedDiscovery.Client.CentralizedDiscovery(serviceDiscoveryHost.MasterUri, bluepathListener2)) { var connectionManager = new Bluepath.Services.ConnectionManager(remoteService: null, listener: bluepathListener1, serviceDiscovery: serviceDiscoveryClient1); TestHelpers.RepeatUntilTrue(() => connectionManager.RemoteServices.Count() == 1, times: 10); connectionManager.RemoteServices.Count().ShouldBe(1); } } } finally { serviceDiscoveryHost.Stop(); bluepathListener1.Stop(); bluepathListener2.Stop(); } }
public void ConnectionManagerRemovesServicesNotExistingInServiceDiscovery() { var manualResetEvent = new System.Threading.ManualResetEvent(false); var serviceUri1 = new ServiceUri() { Address = "jack", BindingType = BindingType.BasicHttpBinding }; var serviceUri2 = new ServiceUri() { Address = "jackie", BindingType = BindingType.BasicHttpBinding }; Dictionary<ServiceUri, PerformanceStatistics> services = new Dictionary<ServiceUri, PerformanceStatistics>() { {serviceUri1, new PerformanceStatistics()}, {serviceUri2, new PerformanceStatistics()} }; var serviceDiscoveryMock = new Mock<IServiceDiscovery>(MockBehavior.Strict); serviceDiscoveryMock.Setup(sd => sd.GetPerformanceStatistics()).Returns(() => services).Callback(() => manualResetEvent.Set()); var manager = new ConnectionManager(remoteService: null, listener: null, serviceDiscovery: serviceDiscoveryMock.Object, serviceDiscoveryPeriod: new TimeSpan(days: 0, hours: 0, minutes: 0, seconds: 0, milliseconds: 10)); manualResetEvent.WaitOne(); System.Threading.Thread.Sleep(10); manager.RemoteServices.Count().ShouldBe(2); services.Remove(serviceUri1); manualResetEvent.Reset(); manualResetEvent.WaitOne(); manager.RemoteServices.Count().ShouldBe(1); }
public void ConnectionManagerHandlesNullRemoteServiceInConstructor() { KeyValuePair<ServiceUri, PerformanceStatistics>? service = null; var manager = new ConnectionManager(service, null); manager.RemoteServices.ShouldBeEmpty(); }
private static void PrepareDLINQEnviroment(out BluepathListener listener1, out BluepathListener listener2, out ConnectionManager connectionManager) { listener1 = new BluepathListener("127.0.0.1", StartPort); listener2 = new BluepathListener("127.0.0.1", StartPort + 1); var availableServices = new Dictionary<ServiceUri, PerformanceStatistics>() { {listener1.CallbackUri, new PerformanceStatistics() { NumberOfTasks = new Dictionary<Bluepath.Executor.ExecutorState, int>() { {Bluepath.Executor.ExecutorState.Faulted, 0}, {Bluepath.Executor.ExecutorState.Finished, 0}, {Bluepath.Executor.ExecutorState.NotStarted, 0}, {Bluepath.Executor.ExecutorState.Running, 0}, } }}, {listener2.CallbackUri, new PerformanceStatistics() { NumberOfTasks = new Dictionary<Bluepath.Executor.ExecutorState, int>() { {Bluepath.Executor.ExecutorState.Faulted, 0}, {Bluepath.Executor.ExecutorState.Finished, 0}, {Bluepath.Executor.ExecutorState.NotStarted, 0}, {Bluepath.Executor.ExecutorState.Running, 0}, } }}, }; connectionManager = new ConnectionManager(availableServices, listener1); }
private static void RunTest(ConnectionManager connectionManager, ThreadNumberScheduler scheduler, Options options) { Log.TraceMessage(Log.Activity.Custom, "Creating data"); var initializeDataThread = DistributedThread.Create( new Func<int, string, IBluepathCommunicationFramework, int>( (dataSize, key, bluepath) => { var data = new List<string>(dataSize); var list = new DistributedList<string>(bluepath.Storage as IExtendedStorage, key); if (list.Count != dataSize) { list.Clear(); } else { return dataSize; } for (int i = 0; i < dataSize; i++) { int nextSourceDocument = i % SourceDocuments.Documents.Count; data.Add(SourceDocuments.Documents[nextSourceDocument]); } Console.WriteLine("Start saving data to redis"); list.AddRange(data); return dataSize; }), connectionManager, scheduler, DistributedThread.ExecutorSelectionMode.LocalOnly); var inputDataKey = "distributedPrefixData"; var numberOfElements = options.NoOfElements; initializeDataThread.Start(numberOfElements, inputDataKey); initializeDataThread.Join(); var expectedSum = (int)initializeDataThread.Result; var numberOfShards = options.NoOfShards; var elementsPerShard = numberOfElements / numberOfShards; var threads = new List<DistributedThread>(); Log.TraceMessage(Log.Activity.Custom, "Running test"); var sw = new Stopwatch(); sw.Start(); for (int i = 0; i < numberOfShards; i++) { int startIndex = i * elementsPerShard; int endIndex; if (i == numberOfShards - 1) { // last element endIndex = numberOfElements; } else { endIndex = startIndex + elementsPerShard; } var thread = DistributedThread.Create( new Func<bool, string, int, int, IBluepathCommunicationFramework, byte[]>( (returnPrefixes, inputKey, indexStart, indexEnd, bluepath) => { var inputList = new DistributedList<string>(bluepath.Storage as IExtendedStorage, inputKey); var inputToProcess = new string[indexEnd - indexStart]; inputList.CopyPartTo(indexStart, inputToProcess.Length, inputToProcess); List<string> results = new List<string>(); for (int x = indexStart; x < indexEnd; x++) { var documentLine = inputToProcess[x - indexStart]; var words = documentLine.Split(' '); var partialResult = new List<string>(); foreach (var word in words) { var stringToProcess = word; for (int si = 0; si < stringToProcess.Length; si++) { string res = ""; if (si == stringToProcess.Length - 1) { res = stringToProcess; } else { res = stringToProcess.Substring(0, si + 1); } partialResult.Add(res); } } results.AddRange(partialResult); if (results.Count > 100000) { results.Clear(); } } if (returnPrefixes) { return new PrefixesResult() { Prefixes = results }.Serialize(); } else { return new PrefixesResult().Serialize(); } }), connectionManager, scheduler ); thread.Start(options.ReturnPrefixes == 1, inputDataKey, startIndex, endIndex); threads.Add(thread); } foreach (var thread in threads) { thread.Join(); if (thread.State == Executor.ExecutorState.Faulted) { Console.WriteLine("Err"); } // Could process prefixes } sw.Stop(); //var clearDataThread = DistributedThread.Create( // new Func<string, IBluepathCommunicationFramework, int>( // (key, bluepath) => // { // var list = new DistributedList<int>(bluepath.Storage as IExtendedStorage, key); // list.Clear(); // return 0; // }), // connectionManager, scheduler, DistributedThread.ExecutorSelectionMode.LocalOnly); //clearDataThread.Start(inputDataKey); //clearDataThread.Join(); Console.WriteLine(sw.ElapsedMilliseconds); }
private static void RunTest(ConnectionManager connectionManager, ThreadNumberScheduler scheduler, Options options) { Log.TraceMessage(Log.Activity.Custom, "Creating data"); var initializeDataThread = DistributedThread.Create( new Func<int, string, IBluepathCommunicationFramework, int>( (dataSize, key, bluepath) => { var data = new List<int>(dataSize); for (int i = 0; i < dataSize; i++) { data.Add(1); } var list = new DistributedList<int>(bluepath.Storage as IExtendedStorage, key); if (list.Count != dataSize) { list.Clear(); list.AddRange(data); } return dataSize; }), connectionManager, scheduler, DistributedThread.ExecutorSelectionMode.LocalOnly); var inputDataKey = "inputData"; var numberOfElements = options.NoOfElements; initializeDataThread.Start(numberOfElements, inputDataKey); initializeDataThread.Join(); var expectedSum = (int)initializeDataThread.Result; var numberOfShards = options.NoOfShards; var elementsPerShard = numberOfElements / numberOfShards; var threads = new List<DistributedThread>(); Log.TraceMessage(Log.Activity.Custom, "Running test"); var sw = new Stopwatch(); sw.Start(); for (int i = 0; i < numberOfShards; i++) { int startIndex = i * elementsPerShard; int endIndex; if (i == numberOfShards - 1) { // last element endIndex = numberOfElements; } else { endIndex = startIndex + elementsPerShard; } var thread = DistributedThread.Create( new Func<string, int, int, IBluepathCommunicationFramework, int>( (inputKey, indexStart, indexEnd, bluepath) => { var inputList = new DistributedList<int>(bluepath.Storage as IExtendedStorage, inputKey); int partialSum = 0; for (int x = indexStart; x < indexEnd; x++) { partialSum += inputList[x]; //System.Threading.Thread.Sleep(1000); } return partialSum; }), connectionManager, scheduler ); thread.Start(inputDataKey, startIndex, endIndex); threads.Add(thread); } int overallSum = 0; foreach (var thread in threads) { thread.Join(); if (thread.State == Executor.ExecutorState.Faulted) { Console.WriteLine("Err"); } overallSum += (int)thread.Result; } sw.Stop(); //var clearDataThread = DistributedThread.Create( // new Func<string, IBluepathCommunicationFramework, int>( // (key, bluepath) => // { // var list = new DistributedList<int>(bluepath.Storage as IExtendedStorage, key); // list.Clear(); // return 0; // }), // connectionManager, scheduler, DistributedThread.ExecutorSelectionMode.LocalOnly); //clearDataThread.Start(inputDataKey); //clearDataThread.Join(); Console.WriteLine(overallSum); Console.WriteLine(sw.ElapsedMilliseconds); }
static void Main(string[] args) { Program.Prefixes = new Dictionary<string, List<string>>(); var options = new Options(); if (CommandLine.Parser.Default.ParseArguments(args, options)) { Bluepath.Log.DistributedMemoryHost = options.RedisHost; Bluepath.Log.WriteInfoToConsole = false; Bluepath.Log.WriteToDistributedMemory = false; var bluepathListener = Bluepath.Services.BluepathListener.InitializeDefaultListener(options.Ip, options.Port); using (var serviceDiscoveryClient = new CentralizedDiscovery.Client.CentralizedDiscovery( new ServiceUri(options.CentralizedDiscoveryURI, BindingType.BasicHttpBinding), bluepathListener )) { using (var connectionManager = new ConnectionManager( remoteService: null, listener: bluepathListener, serviceDiscovery: serviceDiscoveryClient, serviceDiscoveryPeriod: TimeSpan.FromSeconds(1))) { System.Threading.Thread.Sleep(1500); string command = string.Empty; string sharedStorageKey = "loadlist"; var sharedCounterKey = "counter"; Console.WriteLine("Initializing Redis"); var storage = new RedisStorage(options.RedisHost); var list = new DistributedList<string>(storage, sharedStorageKey); Console.WriteLine("List count: {0}", list.Count); var commands = new Dictionary<string, Action>() { {"LOAD", ()=> { var sw = new Stopwatch(); sw.Start(); var scheduler = new RoundRobinLocalScheduler(connectionManager.RemoteServices.Select(s=>s.Key).ToArray()); list.Clear(); var counter = new DistributedCounter(storage, sharedCounterKey); counter.SetValue(0); var localList = new List<string>(); foreach(var file in Directory.EnumerateFiles(options.InputFolder)) { var fileContent = File.ReadAllText(file); localList.Add(fileContent); } list.AddRange(localList); localList.Clear(); var servicesCount = connectionManager.RemoteServices.Count; if(servicesCount==0) { servicesCount = 1; } var calculatedChunkSize = (int)Math.Floor(Convert.ToDouble(list.Count) / servicesCount); if(calculatedChunkSize==0) { calculatedChunkSize = 1; } var threads = new List<DistributedThread>(); for(int i=0;i<servicesCount;i++) { var loadThread = DistributedThread.Create( new Func<string, string, int, IBluepathCommunicationFramework, int>( (inputKey, counterKey, chunkSize, bluepath) => { return LoadDocuments(inputKey, counterKey, chunkSize, bluepath); }), connectionManager, scheduler); loadThread.Start(sharedStorageKey, sharedCounterKey, calculatedChunkSize); threads.Add(loadThread); } foreach (var thread in threads) { thread.Join(); } list.Clear(); sw.Stop(); Console.WriteLine("Loaded in {0}ms", sw.ElapsedMilliseconds); }}, {"SEARCH", ()=> { var services = connectionManager.RemoteServices.Select(s => s.Key).ToArray(); var scheduler = new RoundRobinLocalScheduler(services); var threads = new List<DistributedThread>(); Console.Write("Word part: "); var query = Console.ReadLine(); var sw = new Stopwatch(); sw.Start(); for(int i = 0;(i<services.Length) || i < 1;i++) { var searchThread = DistributedThread.Create( new Func<string,string[]>((searchPhraze) => { List<string> result = new List<string>(); lock(Program.prefixesDictionaryLock) { if(Program.Prefixes.ContainsKey(searchPhraze)) { result = Program.Prefixes[searchPhraze]; } } return result.ToArray(); }), null, scheduler); searchThread.Start(query); threads.Add(searchThread); } var joinedResult = new List<string>(); foreach (var thread in threads) { thread.Join(); joinedResult.AddRange(thread.Result as string[]); } var endResult = joinedResult.Distinct().ToArray(); sw.Stop(); Console.WriteLine(); Console.WriteLine(string.Join("||", endResult)); Console.WriteLine("Found in {0}ms", sw.ElapsedMilliseconds); }}, {"CLEAN", ()=> { var services = connectionManager.RemoteServices.Select(s => s.Key).ToArray(); var scheduler = new RoundRobinLocalScheduler(services); var threads = new List<DistributedThread>(); for(int i = 0;(i<services.Length) || i < 1;i++) { var searchThread = DistributedThread.Create( new Func<int>(() => { List<string> result = null; lock(Program.prefixesDictionaryLock) { Program.Prefixes.Clear(); } return 0; }), null, scheduler); searchThread.Start(); threads.Add(searchThread); } foreach (var thread in threads) { thread.Join(); } }} }; do { Console.WriteLine("Available commands:"); foreach (var key in commands.Keys) { Console.WriteLine(key); } Console.Write("Command['q' to exit]: "); command = Console.ReadLine().ToUpper(); if (commands.ContainsKey(command)) { commands[command](); } } while (command != "Q"); } } } }