我有以下同步代码,运行良好:
private void GenerateExportOutput()
{
using StreamWriter writer = new(Coordinator.OutputDirectory + @"\export.txt");
if (this.WikiPagesToExport.IsEmpty)
{
return;
}
var wanted = new SortedDictionary<string, WikiPage>(this.WikiPagesToExport, StringComparer.Ordinal);
foreach (var title in wanted.Keys)
{
writer.WriteLine(title);
}
}
Run Code Online (Sandbox Code Playgroud)
我想将其更改为异步。所以:
private async Task GenerateExportOutputAsync()
{
using StreamWriter writer = new(Coordinator.OutputDirectory + @"\export.txt");
if (this.WikiPagesToExport.IsEmpty)
{
return;
}
var wanted = new SortedDictionary<string, WikiPage>(this.WikiPagesToExport, StringComparer.Ordinal);
foreach (var title in wanted.Keys)
{
await writer.WriteLineAsync(title).ConfigureAwait(false);
}
await writer.FlushAsync().ConfigureAwait(false);
}
Run Code Online (Sandbox Code Playgroud)
哪个编译。但我使用的分析器之一(Meziantou.Analyzer)现在建议我“更喜欢使用‘await using’”。我从来没有使用过await using(尽管我过去尝试过几次并且总是遇到现在遇到的相同问题)。但我想使用它,所以:
await using StreamWriter writer = …Run Code Online (Sandbox Code Playgroud) 假设我有一个Windows服务,它正在做一些工作,然后在很长一段时间内一直睡眠,一直到来(直到服务关闭).所以在服务的OnStart中,我可以启动一个线程,其入口点如下:
private void WorkerThreadFunc()
{
while (!shuttingDown)
{
DoSomething();
Thread.Sleep(10);
}
}
Run Code Online (Sandbox Code Playgroud)
在服务的OnStop中,我以某种方式设置了shuttingDown标志然后加入线程.实际上可能有几个这样的线程,以及其他线程,都在OnStart中启动并在OnStop中关闭/加入.
如果我想在基于async/await的Windows服务中执行此类操作,似乎我可以让OnStart创建可取消的任务但不等待(或等待)它们,并让OnStop取消这些任务然后Task.WhenAll ().等等().如果我理解正确,上面显示的"WorkerThreadFunc"的等价物可能是这样的:
private async Task WorkAsync(CancellationToken cancel)
{
while (true)
{
cancel.ThrowIfCancellationRequested();
DoSomething();
await Task.Delay(10, cancel).ConfigureAwait(false);
}
}
Run Code Online (Sandbox Code Playgroud)
问题1:呃......对吗?我是异步/等待的新手,仍然试图了解它.
假设这是正确的,现在让我们说DoSomething()调用是(或包括)某些硬件的同步写入I/O. 如果我理解正确:
问题2:那不好?我不应该在基于async/await的程序中的Task中进行同步I/O操作?因为它在I/O发生时从线程池中占用一个线程,而线程池中的线程是一个非常有限的资源?请注意,我可能会有数十名此类工作人员同时使用不同的硬件.
我不确定我是否理解正确 - 我认为这与Stephen Cleary的文章" Task.Run Etiquette例子:不要使用Task.Run错误的东西 "有关,但这是特别关于它的存在在Task.Run中做阻塞工作很糟糕.我不确定如果我只是直接这样做也不好,就像上面的"私人异步任务工作()"例子一样?
假设这也很糟糕,那么如果我理解正确,我应该使用DoSomething的非阻塞版本(如果它尚不存在则创建非阻塞版本),然后:
private async Task WorkAsync(CancellationToken cancel)
{
while (true)
{
cancel.ThrowIfCancellationRequested();
await DoSomethingAsync(cancel).ConfigureAwait(false);
await Task.Delay(10, cancel).ConfigureAwait(false);
}
}
Run Code Online (Sandbox Code Playgroud)
问题3:但是......如果DoSomething来自第三方库,我必须使用并且不能更改,并且该库不会公开DoSomething的非阻塞版本,该怎么办?它只是一个黑色的盒子,在某些时候阻止写入一块硬件.
也许我包装它并使用TaskCompletionSource?就像是:
private async Task WorkAsync(CancellationToken cancel)
{
while (true)
{
cancel.ThrowIfCancellationRequested();
await WrappedDoSomething().ConfigureAwait(false);
await Task.Delay(10, cancel).ConfigureAwait(false);
}
}
private …Run Code Online (Sandbox Code Playgroud) 我用 C# 编写了一个简单的异步 NamedPipeStreamServer 进程,其核心是:
public void Listen()
{
bool shuttingDown = false;
while (!shuttingDown)
{
NamedPipeServerStream serverStream =
new NamedPipeServerStream(
"bobasdfpipe",
PipeDirection.InOut,
254,
PipeTransmissionMode.Message,
PipeOptions.Asynchronous);
IAsyncResult connectionResult =
serverStream.BeginWaitForConnection(
this.HandleConnection,
serverStream);
int waitResult =
WaitHandle.WaitAny(
new[]
{
this.ShutdownEvent,
connectionResult.AsyncWaitHandle
});
switch (waitResult)
{
case 0:
// this.ShutdownEvent
shuttingDown = true;
break;
case 1:
// connectionResult.AsyncWaitHandle
serverStream.EndWaitForConnection(connectionResult);
break;
}
}
}
Run Code Online (Sandbox Code Playgroud)
我还为它编写了一个简单的客户端。客户端(不是异步的)只是打开管道然后退出:
static void Main(string[] args)
{
using (
NamedPipeClientStream clientStream =
new NamedPipeClientStream(
".",
"bobasdfpipe",
PipeDirection.InOut))
{
clientStream.Connect();
} …Run Code Online (Sandbox Code Playgroud) 很久以前,我做了一个小项目,我希望了解温莎城堡.我把它放在一边(在真正学到这么多之前)已经有一段时间了.我现在再次打开它,并更新了NuGet包,并开始收到警告CS0618:
'LoggingFacility.UseNLog()'已经过时了:'应该通过LogUsing()提供记录器工厂实现类型,将来会删除它.
我已经基于此搜索了,但我仍然不清楚我应该做什么来取代现在过时的调用,即:
container.AddFacility<LoggingFacility>(f => f.UseNLog());
Run Code Online (Sandbox Code Playgroud)
任何帮助,将不胜感激.谢谢!
我试图摆脱对VB6应用程序中SCRRUN.DLL的依赖。它当前用于其中的一件事是其Dictionary类。Dictionary类具有一个Keys函数,该函数应该返回字典中的一个键数组。我做了一些实验,看看字典中没有键会发生什么:
Dim D As Dictionary
Set D = New Dictionary
Dim K() As Variant
K = D.Keys
MsgBox LBound(K) & ", " & UBound(K)
Run Code Online (Sandbox Code Playgroud)
我原以为“下标超出范围”或类似的内容,但是我却得知LBound为0,UBound为-1。
那么,如何创建具有LBound 0和UBound -1的Variant数组?
我试过只使用未初始化的变体数组:
Dim K() as Variant
MsgBox LBound(K) & ", " & UBound(K)
Run Code Online (Sandbox Code Playgroud)
但是,当然,正如我所期望的那样,这会使“下标超出范围”。删除未初始化的数组也是如此:
Dim K() as Variant
Erase K
MsgBox LBound(K) & ", " & UBound(K)
Run Code Online (Sandbox Code Playgroud)
与擦除初始化数组一样:
Dim K() As Variant
ReDim K(0 To 0)
Erase K
MsgBox LBound(K) & ", " & UBound(K)
Run Code Online (Sandbox Code Playgroud)
我还尝试过仅将其重新设置为0和-1,这看起来很奇怪:
Dim K() As Variant
ReDim K(0 To …Run Code Online (Sandbox Code Playgroud) .net ×4
asynchronous ×3
c# ×3
async-await ×2
arrays ×1
logging ×1
named-pipes ×1
nlog ×1
variant ×1
vb6 ×1