我的C#应用程序中有简单的方法,它从FTP服务器中挑选文件并解析它并将数据存储在数据库中。我希望它是异步的,以便用户在App上执行其他操作,一旦完成解析,他必须得到消息“解析完成”。
我知道它可以通过异步方法调用来实现,但我不知道该怎么做有人可以帮我吗?
答案 0 :(得分:75)
您需要使用委托及其包含的BeginInvoke
方法异步运行另一个方法。在委托运行的方法结束时,您可以通知用户。例如:
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);
}
}
阅读
答案 1 :(得分:19)
尝试这种方法
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"); } );
答案 2 :(得分:6)
每当你做异步的事情时,你就会使用一个单独的线程,一个新线程,或一个从线程池中获取的线程。这意味着您异步执行的任何操作都必须非常小心与其他线程的交互。
一种方法是将异步线程的代码(称之为线程“A”)及其所有数据放入另一个类(称为类“A”)。确保线程“A”仅访问“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
。请注意,异步任务完成后,仅触摸 。这意味着没有其他任何东西可以干扰任务内部工作,也不会干扰其他任何事情。
答案 3 :(得分:4)
以下是有关C#
中线程的两个链接答案 4 :(得分:4)
在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();
}
答案 5 :(得分:1)
ThreadPool.QueueUserWorkItem是让进程在不同线程上运行的最快方法。
请注意,UI对象具有“线程关联性”,并且无法从创建它们的任何线程访问。
因此,除了检查ThreadPool(或通过委托使用异步编程模型)之外,还需要查看Dispatchers(wpf)或InvokeRequired(winforms)。
答案 6 :(得分:0)
最后,您将不得不使用某种线程。它基本上工作的方式是你用一个新线程启动一个函数,它将一直运行到函数结束。
如果您正在使用Windows窗体,那么他们为此设置的一个很好的包装器就是调用后台工作器。它允许您在后台工作而不需要锁定UI表单,甚至可以提供与表单通信并提供进度更新事件的方法。
答案 7 :(得分:0)
.NET为特有的功能添加了新的关键字 async 。您可以从$lookup
开始挖掘。使功能突兀的最短的通用方法是更改功能 F :
Object F(Object args)
{
...
return RESULT;
}
像这样:
async Task<Object> FAsync(Object args)
{
...
await RESULT_FROM_PROMISE;
...
return RESULT;
}
以上代码中最重要的事情是,当您的代码使用 await 关键字时,它将控制权返回给名为 FAsync 的函数,并进行其他计算,直到返回允许值并继续执行功能 FAsync 中的其余代码。