小编nos*_*tio的帖子

我怎么处理异步任务我不想等待?

我正在编写一个多人游戏服务器,我正在研究新的C#async/await功能可以帮助我的方法.服务器的核心是一个循环,它尽可能快地更新游戏中的所有演员:

while (!shutdown)
{
    foreach (var actor in actors)
        actor.Update();

    // Send and receive pending network messages
    // Various other system maintenance
}
Run Code Online (Sandbox Code Playgroud)

这个循环需要处理数千个演员并每秒更新多次以保持游戏顺利运行.有些演员偶尔会在更新函数中执行缓慢的任务,例如从数据库中获取数据,这是我想要使用异步的地方.一旦检索到该数据,actor就想要更新游戏状态,这必须在主线程上完成.

由于这是一个控制台应用程序,我计划编写一个SynchronizationContext,它可以将挂起的委托分派给主循环.这允许这些任务在完成后更新游戏,并允许将未处理的异常抛入主循环.我的问题是,如何编写异步更新功能?这非常好用,但打破了不使用async void的建议:

Thing foo;

public override void Update()
{
    foo.DoThings();

    if (someCondition) {
        UpdateAsync();
    }
}

async void UpdateAsync()
{
    // Get data, but let the server continue in the mean time
    var newFoo = await GetFooFromDatabase();

    // Now back on the main thread, update game state
    this.foo = newFoo;
}
Run Code Online (Sandbox Code Playgroud)

我可以使Update()异步并将任务传播回主循环,但是:

  • 我不想为数千个永远不会使用它的更新增加开销.
  • 即使在主循环中,我也不想等待任务并阻止循环.
  • 等待任务将导致死锁,因为它需要在等待线程上完成.

我怎么办这些我无法等待的任务?我唯一想知道他们已经完成的时间是关闭服务器的时候,但是我不想收集可能需要数星期更新的每一项任务.

c# asynchronous synchronizationcontext task-parallel-library async-await

11
推荐指数
1
解决办法
9395
查看次数

CoWaitForMultipleHandles API的行为与记录不符

这是由我正在研究的另一个问题引发的.阅读可能太长了,所以请耐心等待.

显然,在MSDN CoWaitForMultipleHandles没有记录的行为.

下面的代码(基于原始问题)是一个控制台应用程序,它启动一个带有测试Win32窗口的STA线程并尝试发布并抽取一些消息.它做了三个不同的测试CoWaitForMultipleHandles,都没有 COWAIT_WAITALL标志.

测试#1旨在验证这一点:

COWAIT_INPUTAVAILABLE如果设置,如果队列输入存在,则对CoWaitForMultipleHandles的调用将返回S_OK,即使已使用对另一个函数(如PeekMessage)的调用看到(但未删除)输入.

这不会发生,CoWaitForMultipleHandles阻塞并且在发出等待句柄之前不会返回.我不认为任何未决的消息应被视为输入(与同MWMO_INPUTAVAILABLEMsgWaitForMultipleObjectsEx,它按预期工作).

测试#2旨在验证这一点:

COWAIT_DISPATCH_WINDOW_MESSAGES允许从ASTA或STA中的CoWaitForMultipleHandles分派窗口消息.ASTA中的默认值是没有调度的窗口消息,STA中的默认值只是一小部分特殊的消息调度.该值在MTA中没有意义,将被忽略.

这也不起作用.当CoWaitForMultipleHandles仅使用COWAIT_DISPATCH_WINDOW_MESSAGES标志调用时,它会立即返回错误CO_E_NOT_SUPPORTED(0x80004021).如果它是一个组合COWAIT_DISPATCH_WINDOW_MESSAGES | COWAIT_DISPATCH_CALLS,则呼叫阻止但不抽取任何消息.

测试#3演示了我可以CoWaitForMultipleHandles使用调用线程的Windows消息队列的唯一方法.它是一个组合COWAIT_DISPATCH_WINDOW_MESSAGES | COWAIT_DISPATCH_CALLS | COWAIT_INPUTAVAILABLE.这确实是泵送和发送消息,尽管显然它是一种无证件的行为.

测试代码(可立即运行的控制台应用程序):

using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleTestApp
{
    static class Program
    {
        // Main 
        static …
Run Code Online (Sandbox Code Playgroud)

.net c# windows com winapi

10
推荐指数
1
解决办法
5106
查看次数

"async void"WPF命令处理程序中的异常处理

我正在审查我的同事的一些WPF代码,这是一个基于组件的,UserControl包含许多async void事件和命令处理程序.这些方法目前不在内部实现任何错误处理.

代码简而言之:

<Window.CommandBindings>
    <CommandBinding
        Command="ApplicationCommands.New"
        Executed="NewCommand_Executed"/>
</Window.CommandBindings>
Run Code Online (Sandbox Code Playgroud)
private async void NewCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
    // do some fake async work (and may throw if timeout < -1)
    var timeout = new Random(Environment.TickCount).Next(-100, 100);
    await Task.Delay(timeout);
}
Run Code Online (Sandbox Code Playgroud)

抛出异常但未在内部观察到的异常NewCommand_Executed 只能在全局级别上处理(例如,使用AppDomain.CurrentDomain.UnhandledException).显然,这不是一个好主意.

我可以在本地处理异常:

private async void NewCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
    try
    {
        // do some fake async work (throws if timeout < -1)
        var timeout = new …
Run Code Online (Sandbox Code Playgroud)

.net c# wpf error-handling async-await

10
推荐指数
1
解决办法
1938
查看次数

WPF 4.5中的INotifyDataErrorInfo和异步数据验证

是否允许ErrorsChanged从非UI线程触发事件?我正在看以下文章:

使用INotifyErrorDataError接口验证WPF 4.5中的数据.

特别是,我有一个关于此代码片段的问题:

private async void ValidateUsername(string username)
{
    const string  propertyKey = "Username";
    ICollection<string> validationErrors = null;
    /* Call service asynchronously */
    bool isValid = await Task<bool>.Run(() => 
    { 
        return _service.ValidateUsername(username, out validationErrors); 
    })
    .ConfigureAwait(false);

    if (!isValid)
    {
        /* Update the collection in the dictionary returned by the GetErrors method */
        _validationErrors[propertyKey] = validationErrors;

        /* Raise event to tell WPF to execute the GetErrors method */
        RaiseErrorsChanged(propertyKey);
    }
    else if(_validationErrors.ContainsKey(propertyKey))
    {
        /* Remove all errors …
Run Code Online (Sandbox Code Playgroud)

.net c# wpf asynchronous async-await

10
推荐指数
1
解决办法
1762
查看次数

AspNetSynchronizationContext并等待ASP.NET中的延续

await内部异步ASP.NET Web API控制器方法之后,我注意到一个意外的(我会说,一个冗余的)线程切换.

例如,下面我希望ManagedThreadId在#2和3#的位置看到相同的内容,但最常见的是我在#3看到一个不同的主题:

public class TestController : ApiController
{
    public async Task<string> GetData()
    {
        Debug.WriteLine(new
        {
            where = "1) before await",
            thread = Thread.CurrentThread.ManagedThreadId,
            context = SynchronizationContext.Current
        });

        await Task.Delay(100).ContinueWith(t =>
        {
            Debug.WriteLine(new
            {
                where = "2) inside ContinueWith",
                thread = Thread.CurrentThread.ManagedThreadId,
                context = SynchronizationContext.Current
            });
        }, TaskContinuationOptions.ExecuteSynchronously); //.ConfigureAwait(false);

        Debug.WriteLine(new
        {
            where = "3) after await",
            thread = Thread.CurrentThread.ManagedThreadId,
            context = SynchronizationContext.Current
        });

        return "OK";
    }
}
Run Code Online (Sandbox Code Playgroud)

我已经看过了实现AspNetSynchronizationContext.Post,基本上归结为:

Task newTask = _lastScheduledTask.ContinueWith(_ => …
Run Code Online (Sandbox Code Playgroud)

.net c# asp.net task-parallel-library async-await

10
推荐指数
1
解决办法
3115
查看次数

未处理的承诺的意外 unhandledRejection 事件,拒绝确实得到处理

更新,我现在已经尝试解释我所看到的行为,但从可靠的来源获得关于行为的答案仍然很棒unhandledRejection。我还在Reddit 上发起了一个讨论


为什么我unhandledRejection在下面的代码中得到一个事件(对于“错误 f1”)?这是出乎意料的,因为我在处理这两个拒绝finally的部分main

我在 Node (v14.13.1) 和 Chrome (v86.0.4240.75) 中看到了相同的行为:

window.addEventListener("unhandledrejection", event => {
  console.warn(`unhandledRejection: ${event.reason.message}`);
});

function delay(ms) {
  return new Promise(r => setTimeout(r, ms));
}

async function f1() {
  await delay(100);
  throw new Error("error f1");
}

async function f2() {
  await delay(200);
  throw new Error("error f2");
}

async function main() {
  // start all at once
  const [p1, p2] = [f1(), f2()]; …
Run Code Online (Sandbox Code Playgroud)

javascript node.js promise async-await es6-promise

10
推荐指数
1
解决办法
2550
查看次数

如何优雅地结束 Google Speech-to-Text 流识别并取回待处理的文本结果?

我希望能够结束 Google 语音到文本流(使用创建streamingRecognize),并取回待处理的 SR(语音识别)结果。

简而言之,相关的 Node.js 代码:

// create SR stream
const stream = speechClient.streamingRecognize(request);

// observe data event
const dataPromise = new Promise(resolve => stream.on('data', resolve));

// observe error event
const errorPromise = new Promise((resolve, reject) => stream.on('error', reject));

// observe finish event
const finishPromise = new Promise(resolve => stream.on('finish', resolve));

// send the audio
stream.write(audioChunk);

// for testing purposes only, give the SR stream 2 seconds to absorb the audio
await new Promise(resolve => setTimeout(resolve, …
Run Code Online (Sandbox Code Playgroud)

javascript speech-recognition node.js async-await google-cloud-speech

10
推荐指数
1
解决办法
1062
查看次数

WebBrowserSite:如何在派生类中调用私有COM接口方法?

这是挑战.我来自Framework的WebBrowserSite类.我的派生类的实例ImprovedWebBrowserSite是通过WebBrowser.CreateWebBrowserSiteBase,我在我的WebBrowser类的派生版本中重写- 特别是提供自定义站点对象.Framework的WebBrowser实现进一步将其传递给底层的非托管WebBrowser ActiveX控件.

到目前为止,我已经设法IDocHostUIHandler在我的ImprovedWebBrowserSite实现中覆盖(像这样).我现在正在寻找更多核心COM接口,比如IOleClientSite,我想要传递给它WebBrowserSite.所有这些都暴露在与COM ComImport,但声明privateinternal由框架实施的WebBrowserSite/ UnsafeNativeMethods.因此,我无法在派生类中明确地重新实现它们.我必须像我一样定义自己的版本IDocHostUIHandler.

所以,问题是,如何WebBrowserSite从我的派生类中调用定义的私有或内部COM接口的方法?例如,我想打电话IOleClientSite.GetContainer.我可以使用反射(像这样),但这将是最后的手段,其次是WebBrowser从头开始重新实现.

我的想法是,因为Framework的私有UnsafeNativeMethods.IOleClientSite和我自己ImprovedWebBrowserSite.IOleClientSite都是COM接口,用ComImport属性声明,相同的GUID和相同的方法签名..NET 4.0+中有COM类型等价,因此必须有一种方法可以在没有反射的情况下完成.

[更新]现在我已经有了一个解决方案,我相信它为自定义WinForms版本WebBrowser控件开启了一些新的和有趣的可能性.

这个版本的问题是在我最初尝试以更抽象的形式表达问题之后创建的,被评论员称为误导.评论已被删除,但我决定保留这两个版本.

为什么我不想用反射来解决这个问题?原因如下:

  • 依赖于实现者给出的内部或私有方法的实际符号名称WebBrowserSite,与COM接口不同,它与二进制v表合同有关.

  • 庞大的反射代码.例如,考虑调用base的私有TranslateAcceleratorvia Type.InvokeMember …

.net c# com com-interop webbrowser-control

9
推荐指数
1
解决办法
1939
查看次数

c#中的Google网站管理员工具API

我想在c#应用程序中使用Google Webmaster Tool API.我浏览了https://developers.google.com上提供的各种文档.不幸的是,我没有得到任何使用.Net的Google WT API的工作示例.我也看过"客户端库"(" https://developers.google.com/gdata/docs/client-libraries ").

任何人都可以向我提供有关如何在c#中使用Google网站管理员工具API的任何实际示例吗?

我在Google WT上有帐号,想要下载.CSV报告"CrawlErrors","InternalLinks","TopSearchQueries"等.

谢谢

.net c# api webservice-client google-webmaster-tools

9
推荐指数
1
解决办法
2331
查看次数

立即从异步方法投掷

从方法抛出的异常的正常行为async Task是保持休眠状态,直到稍后观察它们,或者直到任务被垃圾收集.

我可以想到我可能想立即投掷的情况.这是一个例子:

public static async Task TestExAsync(string filename)
{
    // the file is missing, but it may be there again
    // when the exception gets observed 5 seconds later,
    // hard to debug

    if (!System.IO.File.Exists(filename))
        throw new System.IO.FileNotFoundException(filename);

    await Task.Delay(1000);
}

public static void Main()
{
    var task = TestExAsync("filename");
    try
    {
        Thread.Sleep(5000); // do other work
        task.Wait(); // wait and observe
    }
    catch (AggregateException ex)
    {
        Console.WriteLine(new { ex.InnerException.Message, task.IsCanceled });
    }
    Console.ReadLine();
}
Run Code Online (Sandbox Code Playgroud)

我可以用 …

.net c# task-parallel-library async-await

9
推荐指数
1
解决办法
1006
查看次数