我经常看到它提到Thread.Sleep();
不应该使用,但我不明白为什么会这样.如果Thread.Sleep();
可能造成麻烦,是否有任何替代解决方案具有相同的安全性?
例如.
while(true)
{
doSomework();
i++;
Thread.Sleep(5000);
}
Run Code Online (Sandbox Code Playgroud)
另一个是:
while (true)
{
string[] images = Directory.GetFiles(@"C:\Dir", "*.png");
foreach (string image in images)
{
this.Invoke(() => this.Enabled = true);
pictureBox1.Image = new Bitmap(image);
Thread.Sleep(1000);
}
}
Run Code Online (Sandbox Code Playgroud) 预告:伙计们,这个问题不是关于如何实施重试政策.这是关于正确完成TPL数据流块.
这个问题主要是我之前在ITargetBlock中重试策略的问题的延续.这个问题的答案是@ svick使用TransformBlock
(源)和TransformManyBlock
(目标)的智能解决方案.剩下的唯一问题是以正确的方式完成此块:等待所有重试首先完成,然后完成目标块.这是我最终得到的结果(它只是一个片段,不要过多关注非线程安全retries
集):
var retries = new HashSet<RetryingMessage<TInput>>();
TransformManyBlock<RetryableMessage<TInput>, TOutput> target = null;
target = new TransformManyBlock<RetryableMessage<TInput>, TOutput>(
async message =>
{
try
{
var result = new[] { await transform(message.Data) };
retries.Remove(message);
return result;
}
catch (Exception ex)
{
message.Exceptions.Add(ex);
if (message.RetriesRemaining == 0)
{
if (failureHandler != null)
failureHandler(message.Exceptions);
retries.Remove(message);
}
else
{
retries.Add(message);
message.RetriesRemaining--;
Task.Delay(retryDelay)
.ContinueWith(_ => target.Post(message));
}
return null;
}
}, dataflowBlockOptions);
source.LinkTo(target);
source.Completion.ContinueWith(async …
Run Code Online (Sandbox Code Playgroud) 我正在对代码进行一些单元测试,这可能会根据输入引发许多异常.所以我尝试了类似下面的代码:(简化示例)
static void Main(string[] args)
{
RunTest<ArgumentException>();
}
static void RunTest<T>() where T : Exception, new()
{
try
{
throw new T();
//throw new ArgumentException(); <-- Doesn't work either
}
catch (T tex)
{
Console.WriteLine("Caught passed in exception type");
}
catch (Exception ex)
{
Console.WriteLine("Caught general exception");
}
Console.Read();
}
Run Code Online (Sandbox Code Playgroud)
但是这将始终打印出"抓住一般异常",catch(T tex)处理程序永远不会工作.无论我抛出T()还是显式抛出ArgumentException()都没关系.任何想法为什么会这样?实际上我有点惊讶我甚至能够在catch子句中使用T,但是因为那可能不应该这样做吗?或者至少给出一个编译器警告/错误,说明这个处理程序永远不会工作?
我的环境是Visual Studio 2008,3.5是目标框架.
更新:我现在直接从命令提示符尝试它,然后打印出"Caught传递异常类型".因此看起来这仅限于在Visual Studio中运行.也许Visual Studio托管过程的特殊性?
想象一下WebForms应用程序,其中有一个名为CreateAll()的主方法.我可以一步一步地描述方法任务的过程如下:
1)存储到数据库(更新/创建Db项目3-4次)
2)启动一个新线程
3)Result1 =调用soap服务,并使用超时阈值检查状态和x分钟后.它继续(状态现在正常,这并不意味着失败)
4)存储到数据库(更新/创建Db项目3-4次)
5)result2 =呼叫肥皂服务(以火灾和忘记的方式)
6)更新配置文件(实际上从result1获取)
7)通过使用回调请求,它检查前端的每x秒结果2的状态,UI显示进度条.如果过程结束(100%)则表示成功
我正在考虑所有这些都是可以按类型分组的任务.基本上,几种类型的操作是:
我想为现有实现添加回滚/重试机制,并使用面向任务的体系结构并重构现有的遗留代码.
我发现C#中的Memento Design Pattern或Command Pattern之类的东西可以帮助达到这个目的.我还发现msdn Retry Pattern描述很有趣.我真的不知道,我希望有人带领我做出最安全和最好的决定......
您是否可以建议我保留现有实现和流程的最佳方法,但将其包装在一般的抽象重试/回滚/任务列表实现中?
最终的实现必须能够在每种情况下重试(无论任何任务或一般故障,例如整个createAll流程中的超时等),并且还会有一个回滚决策列表,其中应用程序必须能够回滚已完成的所有任务.
我想要一些例子来打破这个耦合代码.
PseudoCode可能有用:
class something
{
static result CreateAll(object1 obj1, object2 obj2 ...)
{
//Save to database obj1
//...
//Update to database obj1
//
//NEW THREAD
//Start a new thread with obj1, obj2 ...CreateAll
//...
}
void CreateAllAsync()
{
//Type1 Save to database obj1
//...
//Type1 Update to database obj2
//Type2 Call …
Run Code Online (Sandbox Code Playgroud) 我想在捕获异常后再次执行try块中的代码.这有可能吗?
对于Eg:
try
{
//execute some code
}
catch(Exception e)
{
}
Run Code Online (Sandbox Code Playgroud)
如果异常被捕获,我想再次进入try块以"执行一些代码"并再次尝试执行它.
我是Windows Azure开发的新手,并且需要在Windows Azure存储表中存储一些数据.
该表实际上仅用于为位于azure存储驱动器上的某些文件提供快速查找机制.
因此,我计划在应用程序启动时填充此表(即在Web应用程序全局应用程序启动时)
而不是尝试维护此表以更改应用程序未运行时驱动器可能发生的更改.或者因为这个驱动器只是一个资源的vhd,我们可能偶尔上传一个新的vhd.
因此,而不是试图维持这一点的麻烦.在每次应用程序启动时重建此表就足够了.
我开始组合一些代码来检查表是否已经存在,如果它确实删除它,然后重新创建一个新表.
var storageAccount = CloudStorageAccount.Parse(ConfigurationManager.ConnectionStrings["AzureStorage"].ConnectionString);
var tableClient = storageAccount.CreateCloudTableClient();
var rmsTable = tableClient.GetTableReference("ResourceManagerStorage");
rmsTable.DeleteIfExists();
rmsTable.Create();
Run Code Online (Sandbox Code Playgroud)
我曾预料到这不起作用.我收到以下错误:
The remote server returned an error: (409) Conflict.
HTTP/1.1 409 Conflict
Cache-Control: no-cache
Transfer-Encoding: chunked
Server: Windows-Azure-Table/1.0 Microsoft-HTTPAPI/2.0
x-ms-request-id: c6baf92e-de47-4a6d-82b3-4faec637a98c
x-ms-version: 2012-02-12
Date: Tue, 19 Mar 2013 17:26:25 GMT
166
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<error xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
<code>TableBeingDeleted</code>
<message xml:lang="en-US">The specified table is being deleted. Try operation later.
RequestId:c6baf92e-de47-4a6d-82b3-4faec637a98c
Time:2013-03-19T17:26:26.2612698Z</message>
</error>
0
Run Code Online (Sandbox Code Playgroud)
这样做的正确方法是什么?是否有一个事件可以订阅,以便在表被删除时通知您?有关实施此方法的最佳方法的其他建议吗?
我注意到这个问题在我做的大多数事情中发生了很多,所以我认为必须有一个设计模式.
基本上,如果抛出异常,尝试解决问题并重试.如果我把它放在try中,它所做的就是捕获异常,但我想重试它正在做的事情,如果再次失败,再次重试一定次数.
这种东西有共同的模式吗?
我需要在工作流程中引入重试策略.假设有3个块以这种方式连接:
var executionOptions = new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 3 };
var buffer = new BufferBlock<int>();
var processing = new TransformBlock<int, int>(..., executionOptions);
var send = new ActionBlock<int>(...);
buffer.LinkTo(processing);
processing.LinkTo(send);
Run Code Online (Sandbox Code Playgroud)
因此,有一个缓冲区累积数据,然后将其发送到转换块,该转换块一次处理不超过3个项目,然后将结果发送到操作块.
在处理过程中可能会出现变换块瞬态错误,如果错误是瞬态错误,我想重试该块.
我知道块通常不可重试(传递到块中的委托可以重试).其中一个选项是包装传递给支持重试的委托.
我也知道有一个非常好的库TransientFaultHandling.Core
可以为瞬态故障提供重试机制.这是一个很棒的图书馆,但不是我的情况.如果我将传递给转换块的委托包装到RetryPolicy.ExecuteAsync
方法中,则转换块内的消息将被锁定,并且在重试完成或失败之前,转换块将无法接收新消息.想象一下,如果所有3条消息都输入到重试中(假设下次重试尝试将在2分钟内完成)并且失败,则变换块将被卡住,直到至少有一条消息离开变换块.
我看到的唯一的解决办法是延长TranformBlock
(实际上,ITargetBlock
将有足够太),和做手工重试(比如从这里):
do
{
try { return await transform(input); }
catch
{
if( numRetries <= 0 ) throw;
else Task.Delay(timeout).ContinueWith(t => processing.Post(message));
}
} while( numRetries-- > 0 );
Run Code Online (Sandbox Code Playgroud)
ig将消息再次放入变换块中,但是在这种情况下,重试上下文(剩余的重试次数等)也应该传递给该块.听起来太复杂了......
有没有人看到更简单的方法来实现工作流程块的重试策略?
有没有更好的方法来编写这段代码而不使用goto
?这看起来很尴尬,但我想不出更好的方法.我需要能够执行一次重试尝试,但我不想复制任何代码.
public void Write(string body)
{
bool retry = false;
RetryPoint:
try
{
m_Outputfile.Write(body);
m_Outputfile.Flush();
}
catch (Exception)
{
if( retry )
throw;
// try to re-open the file...
m_Outputfile = new StreamWriter(m_Filepath, true);
retry = true;
goto RetryPoint;
}
}
Run Code Online (Sandbox Code Playgroud) 我正在尝试基于这篇文章(但带有任务)实现一些重试逻辑 编写重试逻辑的最干净的方法?
重试逻辑的想法是实现第二个任务,在给定的时间后触发取消
void Main()
{
RetryAction(() => Sleep(), 500);
}
public static void RetryAction(Action action, int timeout)
{
var cancelSource = new CancellationTokenSource();
cancelSource.CancelAfter(timeout);
Task.Run(() => action(), cancelSource.Token);
}
public static void Sleep()
{
System.Threading.Thread.Sleep(5000);
"done".Dump();
}
Run Code Online (Sandbox Code Playgroud)
上面是一个 linqPad 片段(因此是“done”.Dump())
知道为什么 CancelAfter 永远不起作用吗?