using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace ConsoleApp
{
class Program
{
static async Task Main(string[] args)
{
try
{
// Создаём экземпляр класса
var scanner = new Scanner();
// Вызываем асинхронный метод Scan, метод работает
// какое-то время, возвращает результат.
var data = await scanner.Scan();
foreach (var item in data)
{
// Выводим на консоль.
Console.WriteLine(item);
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
public class Scanner
{
public Task<List<string>> Scan()
{
return Task.Run(async () =>
{
var results = new List<string>();
for (int i = 0; i < 10; i++)
{
// Делаем правильную задержку (имитация долгой работы для примера).
await Task.Delay(250);
// Собираем данные
results.Add(DateTimeOffset.Now.ToLocalTime().ToString());
}
return results;
});
}
public async Task<List<string>> ScanVersion2()
{
return await Task.Factory.StartNew(async () =>
{
var results = new List<string>();
for (int i = 0; i < 10; i++)
{
// Делаем правильную задержку (имитация долгой работы для примера).
await Task.Delay(250);
// Собираем данные
results.Add(DateTimeOffset.Now.ToLocalTime().ToString());
}
return results;
}, TaskCreationOptions.LongRunning)
.Unwrap() // Без этого возвращается Task<List<string>>, а не List<string>
.ConfigureAwait(false);
}
}
}
<?php
header('Content-Type: text/html; charset=utf-8');
echo hex2bin('d0bfd180d0b8d0b2d0b5d182');
// текст UTF закодировн в hex чтобы избежать влияния кривых ручек тестировщика/выкрутасов Виндоус
php -S localhost:8081
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
namespace SimpleMessageBus
{
/// <summary>
/// Рассылает события заинтересованным подписчикам
/// в рамках одного приложения.
/// </summary>
/// <remarks>Используются WeakReference, чтобы не было утечек памяти
/// на случай, если кто-то забудет отписаться. Поэтому не рекомендуется
/// использовать лямбда-обработчики событий.</remarks>
public static class MessageBus
{
private static readonly Dictionary<string, List<WeakReference<Action<string, object>>>> Subscribers =
new Dictionary<string, List<WeakReference<Action<string, object>>>>();
/// <summary>
/// Оформляет подписку на событие
/// </summary>
/// <param name="topic">Тип события</param>
/// <param name="handler">Подписчик</param>
public static void Subscribe(string topic,
Action<string, object> handler)
{
if (String.IsNullOrEmpty(topic))
throw new ArgumentNullException(nameof(topic));
if (handler == null)
throw new ArgumentNullException(nameof(handler));
List<WeakReference<Action<string, object>>> handlers;
lock (Subscribers)
if (!Subscribers.TryGetValue(topic, out handlers))
handlers = Subscribers[topic] = new List<WeakReference<Action<string, object>>>();
lock (handlers)
handlers.Add(new WeakReference<Action<string, object>>(handler));
}
/// <summary>
/// Отменяет подписку на событие
/// </summary>
/// <param name="topic">Тип события</param>
/// <param name="handler">Подписчик</param>
public static void Unsubscribe(string topic,
Action<string, object> handler)
{
if (String.IsNullOrEmpty(topic))
throw new ArgumentNullException(nameof(topic));
if (handler == null)
throw new ArgumentNullException(nameof(handler));
List<WeakReference<Action<string, object>>> list;
lock (Subscribers)
if (!Subscribers.TryGetValue(topic, out list))
return;
lock (list)
{
var i = 0;
while (i < list.Count)
{
var reference = list[i];
if (!reference.TryGetTarget(out var target))
list.RemoveAt(i); // Заодно очищаем список от мертвых подписчиков
else if (target == handler)
{
list.RemoveAt(i);
return;
}
}
}
}
/// <summary>
/// Оповещает подписчиков о наступлении события
/// </summary>
/// <param name="topic">Тип события</param>
/// <param name="data">Данные события</param>
public static void Publish(string topic, object data = null)
{
if (String.IsNullOrEmpty(topic))
throw new ArgumentNullException(nameof(topic));
List<WeakReference<Action<string, object>>> list;
lock (Subscribers)
if (!Subscribers.TryGetValue(topic, out list))
return;
var handlers = new List<Action<string, object>>();
lock (list)
{
var i = 0;
while (i < list.Count)
{
var reference = list[i];
if (!reference.TryGetTarget(out var target))
list.RemoveAt(i);
else
{
handlers.Add(target);
++i;
}
}
}
// В Unity вызывать обработчики событий, наверное,
// нужно как-то так:
UnityEngine.WSA.Application.InvokeOnAppThread(() =>
// А в обычном консольном приложении так:
// Task.Run(() =>
{
foreach (var handler in handlers)
{
try
{
handler.Invoke(topic, data);
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
}
}, false);
}
}
}
using System.Diagnostics;
using System.Threading.Tasks;
namespace SimpleMessageBus
{
public static class Program
{
public static async Task Main(string[] args)
{
Debug.WriteLine("Started.");
MessageBus.Subscribe("Rain", RainHandler);
MessageBus.Publish("Rain");
await Task.Delay(100); // Ждем, пока событие поступит
MessageBus.Unsubscribe("Rain", RainHandler);
Debug.WriteLine("Finished.");
}
private static void RainHandler(string topic, object data)
{
Debug.WriteLine("Event: " + topic);
}
}
}
UnityEngine.WSA.Application.InvokeOnAppThread()
— все-таки у нас целевая платформа Unity. иногда есть фризы, например, если открыть пхпшторм, который я уже 2 часа не открывал, или резко перейти с него на фотошоп
AMD или Intel для программиста и (иногда) игрока?
в первом 100 вкладок, во втором 50