C# 如何在异步方法中管理互斥体
我已经将旧的HttpHandler(.ashx)TwitterFeed代码移植到WebAPI应用程序。代码的核心使用了优秀的Linq2Twitter包()。端口的一部分涉及将该组件从版本2升级到版本3,该版本现在提供了许多异步方法调用,这对我来说是新的。以下是基本控制器:C# 如何在异步方法中管理互斥体,c#,asynchronous,synchronization,mutex,linq-to-twitter,C#,Asynchronous,Synchronization,Mutex,Linq To Twitter,我已经将旧的HttpHandler(.ashx)TwitterFeed代码移植到WebAPI应用程序。代码的核心使用了优秀的Linq2Twitter包()。端口的一部分涉及将该组件从版本2升级到版本3,该版本现在提供了许多异步方法调用,这对我来说是新的。以下是基本控制器: public async Task<IEnumerable<Status>> GetTweets(int count, bool includeRetweets, bool excludeReplie
public async Task<IEnumerable<Status>>
GetTweets(int count, bool includeRetweets, bool excludeReplies)
{
var auth = new SingleUserAuthorizer
{
CredentialStore = new SingleUserInMemoryCredentialStore
{
ConsumerKey = ConfigurationManager.AppSettings["twitterConsumerKey"],
ConsumerSecret = ConfigurationManager.AppSettings["twitterConsumerKeySecret"],
AccessToken = ConfigurationManager.AppSettings["twitterAccessToken"],
AccessTokenSecret = ConfigurationManager.AppSettings["twitterAccessTokenSecret"]
}
};
var ctx = new TwitterContext(auth);
var tweets =
await
(from tweet in ctx.Status
where (
(tweet.Type == StatusType.Home)
&& (tweet.ExcludeReplies == excludeReplies)
&& (tweet.IncludeMyRetweet == includeRetweets)
&& (tweet.Count == count)
)
select tweet)
.ToListAsync();
return tweets;
}
如果我注释掉这行代码,代码工作正常,但是(我假设)我应该释放创建它的互斥锁。据我所知,这个问题与创建和释放互斥锁之间的线程变化有关
由于我缺乏异步编码的一般知识,我不确定a)我使用的模式是否可行,b)如果可行,我如何解决问题
任何建议都将不胜感激。像这样使用互斥锁是行不通的。首先,
Mutex
是线程仿射的,因此不能与async
代码一起使用
我注意到的其他问题:
是线程安全的,因此它无论如何都不需要互斥锁(或任何其他保护)缓存
- 异步方法应遵循以下步骤
HttpContext.Cache
是否是最好的缓存,但我会保持原样,因为您的问题更多的是异步代码如何改变缓存模式
因此,我推荐如下:
private const string CacheKey = "TwitterFeed";
public Task<IEnumerable<Status>> GetTweetsAsync(int count, bool includeRetweets, bool excludeReplies)
{
var context = System.Web.HttpContext.Current;
return GetTweetDataAsync(context, count, includeRetweets, excludeReplies);
}
private Task<IEnumerable<Status>> GetTweetDataAsync(HttpContext context, int count, bool includeRetweets, bool excludeReplies)
{
var cache = context.Cache;
Task<IEnumerable<Status>> data = cache[CacheKey] as Task<IEnumerable<Status>>;
if (data != null)
return data;
data = CallTwitterApiAsync(count, includeRetweets, excludeReplies);
cache.Insert(CacheKey, data, null, GetTwitterExpiryDate(), TimeSpan.Zero);
return data;
}
private async Task<IEnumerable<Status>> CallTwitterApiAsync(int count, bool includeRetweets, bool excludeReplies)
{
...
}
private const string CacheKey=“TwitterFeed”;
公共任务GetTweetsAsync(整数计数、bool includeTweets、bool excludeReplies)
{
var context=System.Web.HttpContext.Current;
返回GetTweetDataAsync(上下文、计数、IncludeTweets、excludeReplies);
}
私有任务GetTweetDataAsync(HttpContext上下文、int计数、bool includeReteets、bool excludeReplies)
{
var cache=context.cache;
任务数据=缓存[CacheKey]作为任务;
如果(数据!=null)
返回数据;
数据=CallTwitterApiaAsync(计数,包括推特,不包括回复);
Insert(CacheKey,data,null,GetTwitterExpiryDate(),TimeSpan.Zero);
返回数据;
}
专用异步任务CallTwitterApiaAsync(整数计数、bool includeTweets、bool excludeReplies)
{
...
}
如果两个不同的请求(来自两个不同的会话)在相同的时间请求相同的twitter提要,那么该提要将被请求两次的可能性很小。但我不会为此而失眠。谢谢你,斯蒂芬,非常有帮助。我尝试实现互斥的原因是为了避免来自两个会话的两个Twitter请求。Twitter提要显示在网站的每个页面上,因此我推断,如果提要花了5秒钟返回,那么两个同时请求的可能性相当高,但我接受你的观点。再次非常感谢您的详细解释和示例。如果您缓存任务,那么Twitter提要被请求两次的可能性非常低。这是因为任务在下载开始时就被添加到缓存中,而不是在下载完成时。这实际上非常聪明。我假设,因为它正在缓存一个任务,即使另一个进程在下载之前对缓存发出请求,那么它只是等待任务响应?我发现很难理解这是可能的!对将(未完成的)任务添加到缓存后,任何其他线程都可以从缓存中读取该任务。一个任务可以由任意数量的方法同时等待,当任务完成时,它们都将继续。而且,任务完成后,等待任务不会让步;取而代之的是,wait跟随一个命令并继续同步执行。所以我喜欢将任务存储在缓存中,但这只能通过内存缓存来完成。
if ((mutex != null) && (iOwnMutex))
{
// The following line throws the error:
// Object synchronization method was called from an
// unsynchronized block of code.
mutex.ReleaseMutex();
}
private const string CacheKey = "TwitterFeed";
public Task<IEnumerable<Status>> GetTweetsAsync(int count, bool includeRetweets, bool excludeReplies)
{
var context = System.Web.HttpContext.Current;
return GetTweetDataAsync(context, count, includeRetweets, excludeReplies);
}
private Task<IEnumerable<Status>> GetTweetDataAsync(HttpContext context, int count, bool includeRetweets, bool excludeReplies)
{
var cache = context.Cache;
Task<IEnumerable<Status>> data = cache[CacheKey] as Task<IEnumerable<Status>>;
if (data != null)
return data;
data = CallTwitterApiAsync(count, includeRetweets, excludeReplies);
cache.Insert(CacheKey, data, null, GetTwitterExpiryDate(), TimeSpan.Zero);
return data;
}
private async Task<IEnumerable<Status>> CallTwitterApiAsync(int count, bool includeRetweets, bool excludeReplies)
{
...
}