我在这里想做的是,根据父任务执行,我尝试执行或取消后续的异步任务。我发现很难全神贯注于以下内容的执行并尝试以最优化的方式实现它。我正在寻找一种以最优化的方式编写此内容的方法。
另外,我很困惑为什么即使在抛出异常之后它仍然继续下一次迭代并等待任务找出抛出的异常。我找不到对此的解释。
public static async Task<TOut> AndThen<TIn, TOut>(this Task<TIn> sourceTask, Func<TIn, Task<TOut>> sf, CancellationToken cancelToken)
{
return await sourceTask.ContinueWith(async st => {
var res = await st; // Raising cancel request in here.
cancelToken.ThrowIfCancellationRequested();
return await sf(res);
}, TaskContinuationOptions.NotOnFaulted & TaskContinuationOptions.NotOnCanceled).Unwrap();
}
Run Code Online (Sandbox Code Playgroud) var task = Task.Run(() => DoSomeStuff()).Result;
这里到底发生了什么?
我做了一个小测试:
using System;
using System.Threading.Tasks;
public class Program
{
public static void Main()
{
var r = Task.Run( () => {Thread.Sleep(5000); return 123; }).Result;
Console.WriteLine(r);
}
}
Run Code Online (Sandbox Code Playgroud)
5 秒后打印“123”。那么访问任何此类属性是否可以Task作为调用 ie 的快捷方式,Task.Wait()这样做安全吗?
以前我的代码调用后Task.Delay(5000)立即返回“123”。我在我的问题中修复了这个问题,但将其留在这里作为评论和答案引用它。
我想我的代码有很多弱点,所以请随时分享任何想法。顺便说一句,我的主要问题是,当我尝试执行以下操作时,最后,当我想等待所有任务(通过使用 Task.WaitAll)完成以检查是否有任何异常时,仅仅因为缺少“await”运算符,它真的会让代码的任何部分同步运行吗?
public class Program
{
static bool mock = true;
static readonly object s_lockSource = new object();
static readonly CancellationTokenSource s_tokenSource = new CancellationTokenSource();
static readonly CancellationToken s_token = s_tokenSource.Token;
public static async Task Main()
{
var sw = new Stopwatch();
sw.Start();
IConfigurationRoot config = new ConfigurationBuilder()
.SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
.AddJsonFile("appsettings.json").Build();
var logger = new LiteLogger(new MemoryStream(), config);
logger.Log(LogLevel.Debug, "Fetching data...");
var jsonHelper = new JsonHelper();
IAsyncIO fileService = mock ? new MockAsyncIO() : new FileService(config, s_token);
IAsyncService webService = mock …Run Code Online (Sandbox Code Playgroud) c# console-application task-parallel-library async-await .net-5
我想知道如何重用线程。我有一个 websocket 连接,它不断发送需要完成一些计算的消息。我想将此计算添加到线程中,但不想每次都创建一个新线程。我怎样才能使线程被重用?
client.MsgRecieved.Subscribe(info =>
{
Thread t = new Thread(() => Do_work(info));
};
Run Code Online (Sandbox Code Playgroud)
有没有一种方法可以创建一个线程,为其命名,然后添加Do_work()到该线程上?
编辑:
我每秒从 websocket 收到多条消息。我宁愿让它们在单个队列中等待,而不是全部在新线程上运行。
在这篇文章中,Stephen 描述了在外部 StartNew(参见下面的代码片段)中,TaskScheduler.Current 是我们的 UI 任务调度程序。事实上,下面代码的输出似乎表明所有内容都是在 UI 线程上执行的。然而,当我尝试确认这一点时,我得到了不同的答案:
private void Button_Click(object sender, RoutedEventArgs e)
{
var uiTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
var ui = new TaskFactory(TaskScheduler.FromCurrentSynchronizationContext());
ui.StartNew(() =>
{
Debug.WriteLine("TaskScheduler.Current == UI TaskScheduler: " + (uiTaskScheduler == TaskScheduler.Current));
Debug.WriteLine("UI on thread " + Environment.CurrentManagedThreadId);
Task.Factory.StartNew(() =>
{
Debug.WriteLine("Background work on thread " + Environment.CurrentManagedThreadId);
});
});
}
Run Code Online (Sandbox Code Playgroud)
和输出:
TaskScheduler.Current == UI TaskScheduler: False
UI on thread 1
Background work on thread 1
Run Code Online (Sandbox Code Playgroud)
为什么会uiTaskScheduler == TaskScheduler.Current返回 false?
我在这里遇到了一个问题,你可能知道答案:我只是仍然无法弄清楚。
我在这里为一个简单的场景创建一个种子:为给定的帖子添加“喜欢”。方法签名是:
async Task GeneratePostLike(string postId, string userId, CancellationToken cancellationToken = default) {
return await postLikeService.AddUserLikeToPost(
new PostLikeInput { PostId = postId, UserId = userId },
cancellationToken
);
}
Run Code Online (Sandbox Code Playgroud)
我想随机生成对帖子的点赞。我正在使用随机和其他机制来获取随机数来执行此操作。
当我使用旧的 for 循环块时,它会按照我想要的方式执行。这是我正在使用的说明:
var numberOfLikesForPost = random.Next(1, 100);
var randomUsersForLikes = await userService.GetRandomUsers(numberOfLikesForPost);
for (var likeIndex = 0; likeIndex < numberOfLikesForPost; likeIndex++)
{
var randomUserId = randomUsersForLikes.PickRandom().Id;
await GeneratePostLike(post.Id!, randomUserId, cancellationToken);
}
Run Code Online (Sandbox Code Playgroud)
但是,当我尝试使用 时Task.WhenAll,它只是执行一两次迭代并继续。看起来它的行为就像某种“一劳永逸”的行为。以下代码代表了我对Task.WhenAll块所做的事情:
var numberOfLikesForPost = random.Next(1, 100);
var randomUsersForLikes = await userService.GetRandomUsers(numberOfLikesForPost);
var generatePostLikeTasks …Run Code Online (Sandbox Code Playgroud) 我有一些业务逻辑来检查Web服务是否存在.
我想在开始时间后每隔5分钟重复检查一次.
如何通过任务或线程或等待/异步功能执行此操作.
我正在试验/学习新的Task库,我使用WebClient和Task.Run编写了一个非常简单的html下载器.但是我的网络使用率永远不会超过5%.我想了解为什么以及如何改进我的代码以达到100%的网络使用/吞吐量(可能不可能,但它必须超过5%).
我也希望能够限制线程的数量,但它似乎并不像我想象的那么容易(即自定义任务调度程序).有没有办法只做这样的事情来设置最大线程数:something.SetMaxThread(2)?
internal static class Program
{
private static void Main()
{
for (var i = 0; i < 1000000; i++)
{
Go(i, Thread.CurrentThread.ManagedThreadId);
}
Console.Read();
}
private static readonly Action<int, int> Go = (counter, threadId) => Task.Run(() =>
{
var stopwatch = new Stopwatch();
stopwatch.Start();
var webClient = new WebClient();
webClient.DownloadString(new Uri("http://stackoverflow.com"));
stopwatch.Stop();
Console.Write("{0} == {1} | ", threadId.ToString("D3"), Thread.CurrentThread.ManagedThreadId.ToString("D3"));
Console.WriteLine("{0}: {1}ms ", counter.ToString("D3"), stopwatch.ElapsedMilliseconds.ToString("D4"));
});
}
Run Code Online (Sandbox Code Playgroud)
这是@spender的异步版本.但是我的理解是await将"记住"该时间点并将下载切换到OS级别并跳过(2 console.write)并立即返回main并继续在for循环中调度剩余的Go方法.我理解正确吗?因此UI上没有阻止.
private static async void Go(int counter, int threadId)
{
using …Run Code Online (Sandbox Code Playgroud) 这是我的最低代表案例:
public Form1()
{
Task.Delay(100).Wait(); // Works just fine
this.Await().Wait(); // Blocks indefinitely
}
private async Task Await()
{
await Task.Delay(100);
}
Run Code Online (Sandbox Code Playgroud)
这里发生了什么?为什么这两个表现不一样?我该怎么做才能使后一个工作?
我的实际案例不那么简单,我不能"只使用第一个选项".
我一直在进行异步调用,发现方法的异步版本比同步版本运行慢得多。谁能评论我可能缺少的东西。谢谢。
同步方法时间为00:00:23.5673480
异步方法时间为00:01:07.1628415
每个呼叫返回的总记录/条目= 19972
下面是我正在运行的代码。
--------------------测试课程----------------------
[TestMethod]
public void TestPeoplePerformanceSyncVsAsync()
{
DateTime start;
DateTime end;
start = DateTime.Now;
for (int i = 0; i < 10; i++)
{
using (IPersonRepository repository = kernel.Get<IPersonRepository>())
{
IList<IPerson> people1 = repository.GetPeople();
IList<IPerson> people2 = repository.GetPeople();
}
}
end = DateTime.Now;
var diff = start - end;
Console.WriteLine(diff);
start = DateTime.Now;
for (int i = 0; i < 10; i++)
{
using (IPersonRepository repository = kernel.Get<IPersonRepository>())
{
Task<IList<IPerson>> people1 = GetPeopleAsync();
Task<IList<IPerson>> …Run Code Online (Sandbox Code Playgroud) c# ×10
async-await ×5
task ×3
.net ×2
.net-4.5 ×1
.net-5 ×1
asynchronous ×1
concurrency ×1
deadlock ×1
linq ×1
web-crawler ×1
wpf ×1