任务并行库很棒,在过去的几个月里我经常使用它.但是,有一些事情让我感到困扰:事实TaskScheduler.Current
是默认的任务调度程序,而不是TaskScheduler.Default
.这在文档和样本中乍一看绝对不是很明显.
Current
可以导致细微的错误,因为它的行为正在改变,这取决于你是否在另一个任务中.哪个不容易确定.
假设我正在编写异步方法库,使用基于事件的标准异步模式来表示原始同步上下文的完成,这与XxxAsync方法在.NET Framework中完全相同(例如DownloadFileAsync
).我决定使用任务并行库来实现,因为使用以下代码实现此行为非常容易:
public class MyLibrary
{
public event EventHandler SomeOperationCompleted;
private void OnSomeOperationCompleted()
{
SomeOperationCompleted?.Invoke(this, EventArgs.Empty);
}
public void DoSomeOperationAsync()
{
Task.Factory.StartNew(() =>
{
Thread.Sleep(1000); // simulate a long operation
}, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default)
.ContinueWith(t =>
{
OnSomeOperationCompleted(); // trigger the event
}, TaskScheduler.FromCurrentSynchronizationContext());
}
}
Run Code Online (Sandbox Code Playgroud)
到目前为止,一切运作良好.现在,让我们在WPF或WinForms应用程序中单击按钮调用此库:
private void Button_OnClick(object sender, EventArgs args)
{
var myLibrary = new MyLibrary();
myLibrary.SomeOperationCompleted += (s, e) => DoSomethingElse();
myLibrary.DoSomeOperationAsync(); // call that triggers the …
Run Code Online (Sandbox Code Playgroud) .net c# conceptual synchronizationcontext task-parallel-library
如何在 C# 中为记录类型创建多个构造函数?
我创建了这样的记录类型:
public record Person(int Id, string FirstName, string LastName)
Run Code Online (Sandbox Code Playgroud)
现在我想引入另一个不带参数的构造函数重载,我该怎么做?在正常的课堂上我会做这样的事情:
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Person()
{
}
public Person(int id, string firstName, string lastName)
{
Id = id;
FirstName = firstName;
LastName = lastName;
}
}
Run Code Online (Sandbox Code Playgroud) 我有一本名为d
如上所述的字典。
Dictionary<string, int> d = new Dictionary<string, int>();
d["dog"] = 1;
d["cat"] = 5;
Run Code Online (Sandbox Code Playgroud)
现在,如果我想删除密钥,"cat"
我无法使用该Remove()
方法,因为它只删除关联的相应值,而不删除密钥本身。那么有没有办法删除密钥呢?
我正在尝试运行 a Parallel.ForEachAsync()
,但出现以下两个错误:
错误 1:
参数 2:无法从 System.Threading.Tasks.ParallelOptions 转换为 System.Threading.CancellationToken
错误 2:
Delegate Func<WC, CancellationToken, ValueTask> 不采用 1 个参数
这是我的代码:
public async Task<List<DisplayDto>> GetData()
{
var options = new ParallelOptions()
{
MaxDegreeOfParallelism = 20;
};
await Parallel.ForEachAsync(result, options, async OrderNumber => {
//Do Stuff here.
});
}
Run Code Online (Sandbox Code Playgroud)
为了使其按照我的要求工作,必须改变什么?
Task.WhenAll
在 .NET Core 3.0 上运行时,我只是对该方法进行了一个奇怪的观察。我将一个简单的Task.Delay
任务作为单个参数传递给Task.WhenAll
,并且我预计包装的任务将与原始任务的行为相同。但这种情况并非如此。原始任务的延续是异步执行的(这是可取的),多个Task.WhenAll(task)
包装器的延续是一个接一个同步执行的(这是不可取的)。
这是此行为的演示。四个工作任务正在等待同一个Task.Delay
任务完成,然后继续进行繁重的计算(由 a 模拟Thread.Sleep
)。
var task = Task.Delay(500);
var workers = Enumerable.Range(1, 4).Select(async x =>
{
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff}" +
$" [{Thread.CurrentThread.ManagedThreadId}] Worker{x} before await");
await task;
//await Task.WhenAll(task);
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff}" +
$" [{Thread.CurrentThread.ManagedThreadId}] Worker{x} after await");
Thread.Sleep(1000); // Simulate some heavy CPU-bound computation
}).ToArray();
Task.WaitAll(workers);
Run Code Online (Sandbox Code Playgroud)
这是输出。四个延续在不同的线程(并行)中按预期运行。
var task = Task.Delay(500);
var workers = Enumerable.Range(1, 4).Select(async x =>
{
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff}" +
$" [{Thread.CurrentThread.ManagedThreadId}] Worker{x} before await"); …
Run Code Online (Sandbox Code Playgroud) c# continuations task-parallel-library async-await .net-core
我被教导结构应该几乎总是不可变的,因此记录类与记录结构的这种不寻常行为让我措手不及。
使用记录类...
record class Person(string FirstName, string LastName);
Person p = new("John", "Smith");
p.FirstName = "Jack" // Not allowed!
Run Code Online (Sandbox Code Playgroud)
使用记录结构...
record struct Person(string FirstName, string LastName);
Person p = new("John", "Smith");
p.FirstName = "Jack" // Fine!
Run Code Online (Sandbox Code Playgroud)
使用只读记录结构...
readonly record struct Person(string FirstName, string LastName);
Person p = new("John", "Smith");
p.FirstName = "Jack" // Now allowed!
Run Code Online (Sandbox Code Playgroud)
为什么非readonly
记录结构默认是可变的,为什么相同的行为不适用于记录类?
编辑:我想我在这里问的是,为什么语法......很奇怪?
例如,看起来更合乎逻辑:
record class
-具有值语义的可变引用类型。readonly record class
-具有值语义的不可变引用类型。record struct
-具有值语义的可变值类型。readonly record struct …
class Laziness
{
static string cmdText = null;
static SqlConnection conn = null;
Lazy<Task<Person>> person =
new Lazy<Task<Person>>(async () =>
{
using (var cmd = new SqlCommand(cmdText, conn))
using (var reader = await cmd.ExecuteReaderAsync())
{
if (await reader.ReadAsync())
{
string firstName = reader["first_name"].ToString();
string lastName = reader["last_name"].ToString();
return new Person(firstName, lastName);
}
}
throw new Exception("Failed to fetch Person");
});
public async Task<Person> FetchPerson()
{
return await person.Value;
}
}
Run Code Online (Sandbox Code Playgroud)
Riccardo Terrell 于 2018 年 6 月出版的《.NET 中的并发》一书说道: …
我创建了这个来测试一个并行提取:
public static async Task ExtractToDirectoryAsync(this FileInfo file, DirectoryInfo folder)
{
ActionBlock<ZipArchiveEntry> block = new ActionBlock<ZipArchiveEntry>((entry) =>
{
var path = Path.Combine(folder.FullName, entry.FullName);
Directory.CreateDirectory(Path.GetDirectoryName(path));
entry.ExtractToFile(path);
}, new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 2 });
using (var archive = ZipFile.OpenRead(file.FullName))
{
foreach (var entry in archive.Entries.Where(e => e.Name != string.Empty))
{
block.Post(entry);
}
block.Complete();
await block.Completion;
}
}
Run Code Online (Sandbox Code Playgroud)
以及用于测试的以下单元测试:
[TestMethod]
public async Task ExtractTestAsync()
{
if (Resources.LocalExtractFolder.Exists)
Resources.LocalExtractFolder.Delete(true);
// Resources.LocalExtractFolder.Create();
await Resources.WebsiteZip.ExtractToDirectoryAsync(Resources.LocalExtractFolder);
}
Run Code Online (Sandbox Code Playgroud)
使用MaxDegreeOfParallelism = 1,一切正常,但有两个则没有.
Test Name: ExtractTestAsync
Test FullName: Composite.Azure.Tests.ZipFileTests.ExtractTestAsync …
Run Code Online (Sandbox Code Playgroud) 我最近发现了C# 中的关键字,并且发现如果我理解正确的话,record
它可以用作值类型而不是引用类型。record struct
但是,我很难理解何时确切使用而record struct
不仅仅是struct
. 据我所知,record struct
具有一些结构没有的基本实现(例如==
and!=
运算符、对 的重写ToString
以及其他一些东西),但这就是两者之间的区别吗?如果不是,在决定使用其中一种时需要考虑什么?
从我目前看到的方式来看,最好始终使用record struct
just 来利用它已经附带的那些实现。
我有以下同步代码,运行良好:
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) c# ×10
.net ×4
asynchronous ×4
async-await ×3
c#-9.0 ×2
.net-core ×1
c#-10.0 ×1
conceptual ×1
dictionary ×1
immutability ×1
key ×1
record ×1
struct ×1
tpl-dataflow ×1