All streams
Search
Write a publication
Pull to refresh
0
0

Пользователь

Send message

Мало того что реклама, причем абсолютно бесполезная. У вас стоит 2900, проще купить золото на фп и продлить подписку токеном. Или на других сайтах за 2700 или через дискорды за 2400.

Еще сильнее захотелось уехать из этой страны. Спасибо.

Льготная ипотека 2.0. Очередная мера потдержки застройщиков. Видимо кому то в правительстве хочется стабилизировать цены на недвижку.

Забавно что когда якобы прислушивались к сообществу забыли уточнить что речь идёт о новостройках.

Да действительно, мой пример некорректен. Все встало на свои места.

Вызовите пожалуйста
пример
			ThreadPool.SetMaxThreads(1000, 1000);
			Task.Factory.StartNew(() => {
				var task1 = Task.Factory.StartNew(() => {
					Console.WriteLine($"Task ThreadId {Thread.CurrentThread.ManagedThreadId}");
					Thread.Sleep(10000);
					return -1;
				});
				int mainThreadId = Thread.CurrentThread.ManagedThreadId;
				Console.WriteLine($"mainThreadId {mainThreadId}");
				var task2 = Task.Factory.StartNew(() => {
					for (int i = 0; i < 1000; i++)
					{
						Task.Factory.StartNew(() =>
						{
							if (Thread.CurrentThread.ManagedThreadId == mainThreadId)
							{
								Console.WriteLine($"other thread with id  {Thread.CurrentThread.ManagedThreadId }");
							}
							Console.WriteLine($"thread create  {Thread.CurrentThread.ManagedThreadId }");
							Thread.Sleep(2000);
						});
					}
				});
				int result = task1.Result;
			}).Wait();
			Console.ReadKey();


Как можно объяснить что некоторые задачи запускаются с тем же ThreadId что и Task который в блокировке ждет результата?
image
Вообще-то, ничего не изменится. Просто раньше у вас потоки блокировались на WaitOne, а станут блокироваться на Result.

Соль то реализации в блокировке исполнения до получения сигнала.
Вообще-то, ничего не изменится. Просто раньше у вас потоки блокировались на WaitOne, а станут блокироваться на Result

По поводу блокировке на Result, немного расскажу в чем Task отличается от обычного потока на примере.

Пример 1:
      ThreadPool.SetMaxThreads(1000, 1000);
      var task1 = Task.Factory.StartNew(() => {
        Console.WriteLine($"Task ThreadId {Thread.CurrentThread.ManagedThreadId}");
        Thread.Sleep(10000);
        return -1;
      });
      int mainThreadId = Thread.CurrentThread.ManagedThreadId;
      Console.WriteLine($"mainThreadId {mainThreadId}");
      var task2 = Task.Factory.StartNew(() => {
        for (int i = 0; i < 1000; i++)
        {
          Task.Factory.StartNew(() =>
          {
            if (Thread.CurrentThread.ManagedThreadId == mainThreadId)
            {
              Console.WriteLine($"other thread with id  {Thread.CurrentThread.ManagedThreadId }");
            }
            Console.WriteLine($"thread create  {Thread.CurrentThread.ManagedThreadId }");
            Thread.Sleep(2000);
          });
        }
      });
      int result = task1.Result;
      Console.ReadKey();


Пример 2:
 ThreadPool.SetMaxThreads(1000, 1000);
      Task.Factory.StartNew(() => {
        var task1 = Task.Factory.StartNew(() => {
          Console.WriteLine($"Task ThreadId {Thread.CurrentThread.ManagedThreadId}");
          Thread.Sleep(10000);
          return -1;
        });
        int mainThreadId = Thread.CurrentThread.ManagedThreadId;
        Console.WriteLine($"mainThreadId {mainThreadId}");
        var task2 = Task.Factory.StartNew(() => {
          for (int i = 0; i < 1000; i++)
          {
            Task.Factory.StartNew(() =>
            {
              if (Thread.CurrentThread.ManagedThreadId == mainThreadId)
              {
                Console.WriteLine($"other thread with id  {Thread.CurrentThread.ManagedThreadId }");
              }
              Console.WriteLine($"thread create  {Thread.CurrentThread.ManagedThreadId }");
              Thread.Sleep(2000);
            });
          }
        });
        int result = task1.Result;
        Console.ReadKey();
      });


Второй пример отличается от первого только в том что обернут Task.Factory.StartNew.
То есть вся логика второго примера будет в потоке из пула потоков, первого примера в обычной потоке.
При выполнении первого примера Вы на строке int result = task1.Result; заблокируете поток, во втором случае Вы его не заблокируете а просто переназначите его на другую задачу.
В первом случае Вы не увидете строку other thread with id никогда, во втором же случае Вы увидите её несколько раз так как поток исполнения переназначен на другие задачи а продолжение после int result = task1.Result; по сути является callBackом.
Является ли текущий поток Taskом или обычным потоком можно узнать свойством
Task.CurrentId
Смысл не в том что бы вернуть задачу, а заблокировать выполнение текущего потока до получения сигнала.
Но Вы подкинули пищу как можно оптимизировать данный механизм.
Создать одну задачу внутри класса с блокировкой, остальные потоки в Receive обращаются к Result этой задачи.
Как итог:
  • Нужно блокировать только один поток(внутренний таск)
  • У обычных потоков будет такая же блокировка как и сейчас
  • Поток из пула освободится для выполнения других задач.

Нужно только прикинуть что будет дороже, примитивы синхронизации или вся эта пляска с тасками.
В данной реализации очень легко. Есть метод T Receive(int timeOut);
Не очень понимаю причем тут IObservable и IObserver ведь это интерфейсы по сути представляют callBack.
TaskCompletionSource про результат выполнения задачи
ISignal про получение сигналов о событиях в другом потоке.

Что бы было наглядно вот тест:
		[TestMethod]
		public void PingPong()
		{
			var signal = SignalFactory.GetInstanse<string>();
			var task = Task.Factory.StartNew(() => { 
				for(int i = 0;i<10;i++)
				{
					Debug.WriteLine(signal.Receive());
					Thread.Sleep(30);
					signal.Send("pong");
				}
			});
			Task.Factory.StartNew(() => {
				Thread.Sleep(10);
				for (int i = 0; i < 10; i++)
				{
					signal.Send("ping");
					Debug.WriteLine(signal.Receive());
					Thread.Sleep(30);
				}
			});

			task.Wait();
		}


Результ
ping
pong
ping
pong
ping
pong
ping
pong
ping
pong
ping
pong
ping
pong
ping
pong
ping
pong
ping
В статье есть мысль.
Текущая модель с Task и IAsyncResult а так же TPL в целом решают все проблемы при должном проектировании

Я не утверждаю что область применения такого подхода широка, нет она даже очень специфична.

В качестве примера можно привести asp.net приложение где может быть несколько процессов (сколько выставили в IIS), в каждом процессе несколько потоков.
Вот к Вам пришел клиент и Вам нужно сделать дорогой запрос к базе, как синхронизировать потоки так что бы был только один запрос?
DataFlow Blocks очень годная штука.
В частности если взять BufferBlock при вызове Receive только один поток получит сигнал который отправили в Post. Пример:

var bufferBlock = new BufferBlock<int>();

Task.Factory.StartNew(() => {
	for (int i = 0; i < 3; i++)
	{
		Thread.Sleep(3000);
		bufferBlock.Post(i);
	}
});
Task.Factory.StartNew(() => {
	for (int i = 0; i < 3; i++)
	{
		Console.WriteLine($"{bufferBlock.Receive()} threadId={Thread.CurrentThread.ManagedThreadId}");
	}
});

for (int i = 0; i < 3; i++)
{
	Console.WriteLine($"{bufferBlock.Receive()} threadId={Thread.CurrentThread.ManagedThreadId}");
}


Основная моя идея это не создание очереди сообщений а синхронизация потоков в том числе в разных процессах.
Для идентификации потока, Вы не можете идентифицировать кто пришел в метод Receive кроме как по ThreadId.
Какого поведения ожидаете в случае, если источник эмитит собщение до того, как поток-потребитель обработал предыдущее?


Это проблемы потока потребителя. Можно в дальнейшем реализовать очередь если необходимо, но если между методами Receive() прошло какое то сообщение то поток соответственно его пропустит.

Использования Monitor вполне интересно.
Если Вам нужно выполнить какую то задачу то действительно лучше использовать Task. Если Вы ждете выполнения какого то события и обработку не желательно осуществлять в том потоке которое спровоцировало событие то сигналы это вариант.
AutoResetEvent привязан к ThreadId в
Dictionary<int,AutoResetEvent> events = new Dictionary<int, AutoResetEvent>();
На ум приходит централизованная обработка каких то событий в приложении простой отправкой сигнала.Синхронизировать потоки так же вполне удобно.
Что же касается межпроцессорных сигналов то можно применить такой сценарий -> запускаем процесс который что то делает -> ждем от него сигнал -> обрабатываем.

Information

Rating
Does not participate
Location
Ростов-на-Дону, Ростовская обл., Россия
Registered
Activity