Как создать асинхронный метод
У меня есть простой метод в моем приложении С#, он выбирает файл с FTP-сервера и анализирует его и сохраняет данные в БД. Я хочу, чтобы он был асинхронным, чтобы пользователь выполнял другие операции над приложением, как только разбор выполняется, он должен получить сообщение о том, что "Parsing is done".
Я знаю, что это может быть достигнуто с помощью асинхронного вызова метода, но Я не знаю, как это сделать. Кто-нибудь может мне помочь?
Ответы
Ответ 1
Вам нужно использовать делегаты и метод BeginInvoke
, который они содержат, для асинхронного запуска другого метода. A конец метода, выполняемого делегатом, вы можете уведомить пользователя. Например:
class MyClass
{
private delegate void SomeFunctionDelegate(int param1, bool param2);
private SomeFunctionDelegate sfd;
public MyClass()
{
sfd = new SomeFunctionDelegate(this.SomeFunction);
}
private void SomeFunction(int param1, bool param2)
{
// Do stuff
// Notify user
}
public void GetData()
{
// Do stuff
sfd.BeginInvoke(34, true, null, null);
}
}
Читайте на http://msdn.microsoft.com/en-us/library/2e08f6yc.aspx
Ответ 2
попробуйте этот метод
public static void RunAsynchronously(Action method, Action callback) {
ThreadPool.QueueUserWorkItem(_ =>
{
try {
method();
}
catch (ThreadAbortException) { /* dont report on this */ }
catch (Exception ex) {
}
// note: this will not be called if the thread is aborted
if (callback!= null) callback();
});
}
Использование:
RunAsynchronously( () => { picks file from FTP server and parses it},
() => { Console.WriteLine("Parsing is done"); } );
Ответ 3
В любое время, когда вы делаете что-то асинхронное, вы используете отдельный поток, либо новый поток, либо один из пула потоков. Это означает, что все, что вы делаете асинхронно, должно быть очень осторожным в отношении взаимодействия с другими потоками.
Один из способов сделать это - поместить код для потока async (назовем его потоком "A" ) вместе со всеми его данными в другой класс (назовите его классом "A" ). Убедитесь, что поток "A" только обращается к данным в классе "A". Если нить "А" касается только класса "А" , и ни одна другая нить не касается данных класса "А" , то есть еще одна проблема:
public class MainClass
{
private sealed class AsyncClass
{
private int _counter;
private readonly int _maxCount;
public AsyncClass(int maxCount) { _maxCount = maxCount; }
public void Run()
{
while (_counter++ < _maxCount) { Thread.Sleep(1); }
CompletionTime = DateTime.Now;
}
public DateTime CompletionTime { get; private set; }
}
private AsyncClass _asyncInstance;
public void StartAsync()
{
var asyncDoneTime = DateTime.MinValue;
_asyncInstance = new AsyncClass(10);
Action asyncAction = _asyncInstance.Run;
asyncAction.BeginInvoke(
ar =>
{
asyncAction.EndInvoke(ar);
asyncDoneTime = _asyncInstance.CompletionTime;
}, null);
Console.WriteLine("Async task ended at {0}", asyncDoneTime);
}
}
Обратите внимание, что единственная часть AsyncClass
, которая коснулась извне, - это общедоступный интерфейс, а единственной частью данных, которая является данными, является CompletionTime
. Обратите внимание, что это происходит только после завершения асинхронной задачи. Это означает, что ничто другое не может помешать выполнению задач внутренней работы и не может вмешиваться в что-либо еще.
Ответ 4
Вот две ссылки о потоковом в С#
Я начал бы читать о BackgroundWorker class
Ответ 5
В Asp.Net я использую много статических методов для выполнения заданий. Если это просто работа, где мне нужен без ответа или статус, я делаю что-то простое, как показано ниже. Как вы можете видеть, я могу выбрать вызов ResizeImages или ResizeImagesAsync в зависимости от того, хочу ли я ждать завершения или нет.
Объяснение кода: Я использую http://imageresizing.net/ для изменения размера/обрезки изображений, а метод SaveBlobPng - для сохранения изображений в Azure (облако), но так как это не имеет значения для этой демонстрации, я не включил этот код. Это хороший пример трудоемких задач, хотя
private delegate void ResizeImagesDelegate(string tempuri, Dictionary<string, string> versions);
private static void ResizeImagesAsync(string tempuri, Dictionary<string, string> versions)
{
ResizeImagesDelegate worker = new ResizeImagesDelegate(ResizeImages);
worker.BeginInvoke(tempuri, versions, deletetemp, null, null);
}
private static void ResizeImages(string tempuri, Dictionary<string, string> versions)
{
//the job, whatever it might be
foreach (var item in versions)
{
var image = ImageBuilder.Current.Build(tempuri, new ResizeSettings(item.Value));
SaveBlobPng(image, item.Key);
image.Dispose();
}
}
Или для потоковой передачи, поэтому вам не нужно беспокоиться о делегатах
private static void ResizeImagesAsync(string tempuri, Dictionary<string, string> versions)
{
Thread t = new Thread (() => ResizeImages(tempuri, versions, null, null));
t.Start();
}
Ответ 6
ThreadPool.QueueUserWorkItem - это самый быстрый способ запустить процесс в другом потоке.
Имейте в виду, что объекты пользовательского интерфейса имеют "сходство потоков" и не могут быть доступны из любого потока, отличного от того, который их создал.
Итак, помимо проверки ThreadPool (или с использованием модели асинхронного программирования через делегатов), вам нужно проверить Dispatchers ( wpf) или InvokeRequired (winforms).
Ответ 7
В конце вам придется использовать какую-то резьбу. Принцип работы в основном заключается в том, что вы запускаете функцию с новым потоком, и она будет работать до конца функции.
Если вы используете Windows Forms, тогда хорошая обертка, которую они имеют для этого, вызывает фоновый рабочий. Он позволяет работать в фоновом режиме без блокировки формы пользовательского интерфейса и даже обеспечивает способ общения с формами и обновления событий обновления.
Фоновый работник