首页 文章

以线程或任务方式启动异步方法

提问于
浏览
6

我是 C# s await/async 的新手,目前正在玩一下 .

在我的场景中,我有一个简单的客户端对象,它具有 WebRequest 属性 . 客户端应定期发送 WebRequest RequestStream 上的活动消息 . 这是client-object的构造函数:

public Client()
{
    _webRequest = WebRequest.Create("some url");
    _webRequest.Method = "POST";

    IsRunning = true;

    // --> how to start the 'async' method (see below)
}

和async alive-sender方法

private async void SendAliveMessageAsync()
{
    const string keepAliveMessage = "{\"message\": {\"type\": \"keepalive\"}}";
    var seconds = 0;
    while (IsRunning)
    {
        if (seconds % 10 == 0)
        {
            await new StreamWriter(_webRequest.GetRequestStream()).WriteLineAsync(keepAliveMessage);
        }

        await Task.Delay(1000);
        seconds++;
    }
}

该方法应该如何开始?

new Thread(SendAliveMessageAsync).Start();

要么

Task.Run(SendAliveMessageAsync); //将返回类型更改为Task

要么

await SendAliveMessageAsync(); //失败,因为构造函数不是异步的

我的问题更多是关于我个人对_2680320的理解,我想在某些方面可能是错的 .

第三种选择是投掷

The 'await' operator can only be used in a method or lambda marked with the 'async' modifier

5 回答

  • 0

    该方法应该如何开始?

    我投票赞成“以上都不是” . :)

    "Fire and forget"是一个难以正确处理的方案 . 特别是,错误处理总是有问题的 . 在这种情况下, async void 可能会让您感到惊讶 .

    如果我不是立即执行任务,我更愿意明确保存任务:

    private async Task SendAliveMessageAsync();
    
    public Task KeepaliveTask { get; private set; }
    
    public Client()
    {
      ...
      KeepaliveTask = SendAliveMessageAsync();
    }
    

    这至少允许 Client 的使用者检测并从 SendAliveMessageAsync 方法抛出的异常中恢复 .

    另外,这个模式几乎等同于我的"asynchronous initialization" pattern .

  • 7

    编辑为先前的答案是错误的:

    因为它在构造函数中,我认为你必须为它启动一个新的线程 . 我个人会这样做

    Task.Factory.StartNew(()=> SendAliveMessageAsync());

  • 0

    由于它是 fire and forget 操作,您应该使用它来启动它

    SendAliveMessageAsync();
    

    请注意 await 不会启动新的 Task . 等待 Task 完成只是语法糖 .
    使用 Task.Run 启动新线程 .

    所以在 SendAliveMessageAsync 内你应该开始一个新的任务:

    private async Task SendAliveMessageAsync()
    {
        const string keepAliveMessage = "{\"message\": {\"type\": \"keepalive\"}}";
        await Task.Run( () => {
            var seconds = 0;
            while (IsRunning)
            {
                if (seconds % 10 == 0)
                {
                    await new StreamWriter(_webRequest.GetRequestStream()).WriteLineAsync(keepAliveMessage);
                }
    
                await Task.Delay(1000);
                seconds++;
            }
        });
    }
    
  • 3

    这里's an option since you can' t从构造函数中调用 await .

    我建议使用微软的Reactive Framework(NuGet“Rx-Main”) .

    代码如下所示:

    public class Client
    {
        System.Net.WebRequest _webRequest = null;
        IDisposable _subscription = null;
    
        public Client()
        {
            _webRequest = System.Net.WebRequest.Create("some url");
            _webRequest.Method = "POST";
    
            const string keepAliveMessage = "{\"message\": {\"type\": \"keepalive\"}}";
    
            var keepAlives =
                from n in Observable.Interval(TimeSpan.FromSeconds(10.0))
                from u in Observable.Using(
                    () => new StreamWriter(_webRequest.GetRequestStream()),
                    sw => Observable.FromAsync(() => sw.WriteLineAsync(keepAliveMessage)))
                select u;
    
            _subscription = keepAlives.Subscribe();
        }
    }
    

    此代码处理所需的所有线程并正确处理 StreamWriter .

    每当你想要停止保持活动时,只需致电 _subscription.Dispose() .

  • 0

    在您的代码中,不需要使用async / await,只需设置一个新线程来执行长操作 .

    private void SendAliveMessage()
    {
        const string keepAliveMessage = "{\"message\": {\"type\": \"keepalive\"}}";
        var sreamWriter = new StreamWriter(_webRequest.GetRequestStream());
        while (IsRunning)
        {
            sreamWriter.WriteLine(keepAliveMessage);
            Thread.Sleep(10 * 1000);
        }    
    }
    

    使用 Task.Factory.StartNew(SendAliveMessage, TaskCreationOptions.LongRunning) 执行操作 .

    如果你真的想使用async / await模式,只需在构造函数中调用它而不使用await修饰符并忘记它 .

    public Client()
    {
        _webRequest = WebRequest.Create("some url");
        _webRequest.Method = "POST";
    
        IsRunning = true;
    
        SendAliveMessageAsync();    //just call it and forget it.
    }
    

    我认为设置一个长时间运行的线程或使用async / await模式并不是一个好主意 . 定时器可能更适合这种情况 .

相关问题