TL; DR:支持服务器GC的应用程序显示数十个特殊的GC线程并超时挂起.有什么可以解释的?
这些天我一直处于.NET服务上出现的奇怪的多线程/争用问题上.症状如下:

我立即怀疑我们的代码中存在一个问题,该问题会导致托管线程池随着时间的推移启动大量线程,所有这些都试图共享一个或多个公共资源.似乎我们对ThreadPool的使用非常小并且非常有用.
我设法获得一个非挂起服务的转储文件,该服务已经拥有非常多的线程(超过100,在正常状态下它应该是20左右)
使用windbg + sos,我们确定ThreadPool大小正常:
0:000> !threadpool
CPU utilization: 0%
Worker Thread: Total: 8 Running: 1 Idle: 7 MaxLimit: 32767 MinLimit: 32
Work Request in Queue: 0
--------------------------------------
Number of Timers: 1
--------------------------------------
Completion Port Thread:Total: 1 Free: 1 MaxFree: 64 CurrentLimit: 1 MaxLimit: 1000 MinLimit: 32
Run Code Online (Sandbox Code Playgroud)
只有8个工作线程......然后我列出了所有托管线程堆栈,发现了很多我无法识别的线程堆栈.请参阅下面的一个示例:
0:000> !eestack
(...)
Thread 94
Current frame: ntdll!NtWaitForSingleObject+0xa
Child-SP RetAddr Caller, Callee
0000008e25b2f770 000007f8f5a210ea KERNELBASE!WaitForSingleObjectEx+0x92, calling ntdll!NtWaitForSingleObject
0000008e25b2f810 000007f8ece549bf clr!CLREventBase::WaitEx+0x16c, calling …Run Code Online (Sandbox Code Playgroud) 我现在使用System.Reflection.Emit一段时间了,发现它(谁没有?)像容易出错一样痛苦.
你知道IL Generator周围是否有一个好的包装器,我可以依赖它以比直接使用SRE更安全,更容易的方式发出IL吗?
编辑:
我知道操纵表达树比直接发射IL更容易和更安全,但它们现在也有一些限制.我不能创建代码块,使用循环,声明和使用几个本地,等等.我们需要等到.NET 4出来:)
此外,我正在处理已经依赖于SRE的代码库.
显然,ILGenerator会做我需要的一切.但是在操纵它时我会感激更多的帮助.当我指的是一个非常低级别的ILGenerator包装器时,我想到的东西可以提供如下方法:
// Performs a virtual or direct call on the method, depending if it is a
// virtual or a static one.
Call(MethodInfo methodInfo)
// Pushes the default value of the type on the stack, then emit
// the Ret opcode.
ReturnDefault(Type type)
// Test the object type to emit the corresponding push
// opcode (Ldstr, Ldc_I*, Ldc_R*, etc.)
LoadConstant(object o)
Run Code Online (Sandbox Code Playgroud)
这真的是3个天真的例子,但它足以证明我的期望.我们可以看到它作为一组扩展方法,但是在RunSharp中支持条件语句和循环可能会很好.实际上,RunSharp与我想要的非常接近,但它过多地抽象了ILGenerator并且没有公开它的所有功能.
我不记得在哪里,但我已经在开源项目中看到过这样的帮手.
我有一个有趣的问题:给定一个IEnumerable<string>,是否有可能IEnumerable<IEnumerable<string>>在一次传递中产生一组相同的相邻字符串?
让我解释.
1.基本说明性样本:
考虑以下IEnumerable<string>(伪表示):
{"a","b","b","b","c","c","d"}
Run Code Online (Sandbox Code Playgroud)
如何获得一个IEnumerable<IEnumerable<string>>会产生某种形式的东西:
{ // IEnumerable<IEnumerable<string>>
{"a"}, // IEnumerable<string>
{"b","b","b"}, // IEnumerable<string>
{"c","c"}, // IEnumerable<string>
{"d"} // IEnumerable<string>
}
Run Code Online (Sandbox Code Playgroud)
方法原型将是:
public IEnumerable<IEnumerable<string>> Group(IEnumerable<string> items)
{
// todo
}
Run Code Online (Sandbox Code Playgroud)
但它也可能是:
public void Group(IEnumerable<string> items, Action<IEnumerable<string>> action)
{
// todo
}
Run Code Online (Sandbox Code Playgroud)
...... action每个子序列都会被调用.
2.更复杂的样本
好的,第一个样本非常简单,只是为了使高级意图清晰.
现在假设我们正在处理IEnumerable<Anything>,在这里Anything定义的类型如下:
public class Anything
{
public string Key {get;set;}
public double Value {get;set;}
}
Run Code Online (Sandbox Code Playgroud)
我们现在想要生成基于Key的子序列(Anything将具有相同键的每个连续组分组)以便稍后使用它们以便按组计算总值:
public void Compute(IEnumerable<Anything> items) …Run Code Online (Sandbox Code Playgroud) 我最近尝试使用NAnt(beta 0.86.2962.0)运行一些使用NUnit(v2.4.8)的最后一个稳定版本编译的单元测试,但没有任何成功.
我得到的错误如下:
[nunit2]程序集"C:\ Dev\MySample\bin\tests\My.Sample.Tests.dll"不包含任何测试.
当然,程序集包含可以从任何运行程序运行的测试,例如NUnit one,TestDriven或Resharper.我想使用<nunit2>任务,而不是直接使用<exec>,但我想知道它是否仍然可行,甚至使用app.config文件来绑定程序集版本.
假设我有以下界面,我想在我的服务器(常规Web服务)和我的客户端(silverlight 2.0应用程序)之间共享:
public interface ICustomerService
{
Customer GetCustomer(string name);
}
Run Code Online (Sandbox Code Playgroud)
我的Web服务实现了这个接口,并引用了一个Customer定义了类型的类库.
通常,如果您想从WCF客户端(例如winforms应用程序)使用此服务,则可以共享模型程序集和服务合同接口.然后,通过使用a ChannelFactory,您可以动态创建实现服务接口的代理.就像是:
ICustomerService myService = new ChannelFactory<ICustomerService>(myBinding, myEndpoint);
Customer customer = myService.GetCustomer("romain");
Run Code Online (Sandbox Code Playgroud)
我基本上想要做同样的事情,但是从Silverlight 2.0应用程序.银光ChannelFactory似乎不像另一个......
你知道这是否可能?
注意:由于Silverlight应用程序只能引用Silverlight项目,因此我有:
两个版本的MyModel.dll包含Customer类型:
两个版本的MyServicesContracts.dll包含ICustomerService接口:
我是一个.NET人 - 我主要使用C#编写代码.
从C#3.0开始,我们可以利用lambda表达式和表达式树来使用静态反射.例如,可以GetMethodName在以下代码段中实现返回参数中传递的方法的名称:
string methodName = GetMethodName( o => o.DoSomething());
Console.WriteLine(methodName); // displays "DoSomething"
Run Code Online (Sandbox Code Playgroud)
现在,当我在Java世界中查看Mockito样本(或EasyMock样本)时,我看到:
LinkedList mockedList = mock(LinkedList.class);
when(mockedList.get(0)).thenReturn("first");
Run Code Online (Sandbox Code Playgroud)
它是如何工作的?
该when方法如何工作?它mockedList.get(0)是如何解释为对get方法的调用,0作为参数而不是作为值传递?
假设我想序列化,然后使用protobuf-net反序列化小数:
const decimal originalDecimal = 1.6641007661819458m;
using (var memoryStream = new MemoryStream())
{
Serializer.Serialize(memoryStream, originalDecimal);
memoryStream.Position = 0;
var deserializedDecimal = Serializer.Deserialize<decimal>(memoryStream);
Assert.AreEqual(originalDecimal, deserializedDecimal);
}
Run Code Online (Sandbox Code Playgroud)
它工作正常.Protobuf-net内部使用以下小数表示(参见Bcl.proto):
message Decimal {
optional uint64 lo = 1; // the first 64 bits of the underlying value
optional uint32 hi = 2; // the last 32 bis of the underlying value
optional sint32 signScale = 3; // the number of decimal digits, and the sign
}
Run Code Online (Sandbox Code Playgroud)
现在说我用代码定义了一个假定的等价原型合约:
[ProtoContract]
public class MyDecimal
{ …Run Code Online (Sandbox Code Playgroud) 我有以下类型:
// incomplete class definition
public class Person
{
private string name;
public string Name
{
get { return this.name; }
}
}
Run Code Online (Sandbox Code Playgroud)
我希望使用某种专用控制器/构建器创建和更新此类型,但我希望它对其他类型保持只读.
每次由控制器/构建器更新事件时,此对象还需要触发事件.
总结一下,根据以前的类型定义骨架:
Person只能通过特定的控制器被实例化Person(name字段)的状态Person需要一个发送通知到世界其他地方发生时Person属性我该如何实现呢?我在这里谈论的是控制器/构建器,但欢迎所有其他解决方案.
注意:我可以依赖internal修饰符,但理想情况下我的所有东西都应该在同一个程序集中.
c# ×6
.net ×5
algorithm ×1
c++ ×1
cil ×1
clr ×1
decimal ×1
easymock ×1
ienumerable ×1
ilgenerator ×1
java ×1
licensing ×1
mockito ×1
nant ×1
nunit ×1
open-source ×1
performance ×1
protobuf-net ×1
reflection ×1
silverlight ×1
unit-testing ×1
wcf ×1
windbg ×1