大规模视频网站的计费与流量管理
本次分享将会就大规模视频网站的计费与流量管理这个话题,从操作层面细细进行讲解和分析,为系统工程师们揭示平日里我们没有关心的另一些内容。同时也希望本次分享能揭示行业中的一些“潜规则”,让互联网行业的流量与带宽管理更为开放与简洁。
本次演讲视频录制于QCon杭州2011。
该内容已经被标记书签!
标记书签错误,请重试!

作者 Jonathan Allen 译者 曹云飞 发布于 2008年6月2日
重写相等操作符是非常容易出错的。不仅因为相等操作符有许多内涵,而且目前有很多指导文档有瑕疵,甚至在MSDN网站上有些指导文档也有瑕疵。我们将分别对支持相等操作的引用类型和值类型给出系统的分析,来澄清事实。
为了清晰起见,这里将类称作引用类型而结构称作值类型。
通常在结构中操作符重载比在类中有意义,所以我们先来展示在结构中的情况。类和结构的主要区别是,类需要检查空值,而在结构中你需要意识到可能存在的类型装箱。这一点将在后面说明。
结构的签名是直接了当的。你仅仅需要用System.IEquatable接口来标识该结构。请注意这个接口没有非泛型的版本,泛型的版本的角色由基础类Object承担。
C#
struct PointStruct : System.IEquatable
VB
Public Structure PointStruct
Implements IEquatable(Of PointStruct)
类的签名本质上和结构签名是一样的。类的继承会破坏相等性,这会造成问题。如果a是一个基类而b是一个重写了Equals方法的子类,那么 a.Equals(b)会返回与b.Equals(a)不同的返回值。后面我们通过封闭(sealing)的Equals方法来解决这个问题。
C#
class PointClass : System.IEquatable
VB
Public Class PointClass Implements IEquatable(Of PointClass)
任何用于相等性比较的成员变量必须是不可变的。通常,这意味着类中所有的属性是只读的或者类有一个类似于数据库主键的唯一标识符。
在使用任何依赖哈希的东西的时候这条规则都是至关重要的。这样的例子包括Hashtable、Dictionary、HashSet和 KeyedCollection。这些类都使用哈希码作查找和存储。如果对象的哈希码变化了,它会被放在错误的槽中而且集合不能再正确的工作。最常见的故障是不能找到以前放在集合中的对象。
为了确保成员变量是不可变的,它们被标记为只读的。由于成员变量可以在构造器中设置,所以改变成员变量有点象写错名字。但是一旦初始化完成了,没有方法可以直接改变成员变量的值。
C#
readonly int _X;
readonly int _Y;
public PointStruct (int x, int y)
{
_X = x;
_Y = y;
}
int X
{
get { return _X; }
}
int Y
{
get { return _Y; }
}
VB
Private ReadOnly m_X As Integer
Private ReadOnly m_Y As Integer
Public Sub New(ByVal x As Integer, ByVal y As Integer)
m_X = x
m_Y = y
End Sub
Public ReadOnly Property X() As Integer
Get
Return m_X
End Get
End Property
Public ReadOnly Property Y() As Integer
Get
Return m_Y
End Get
End Property
由于类版本的代码与上面的代码几乎是相同的,且在VB中是完全相同的,所以这里不给出类版本代码。
我们实现的第一个方法是类型安全的相等方法,在IEquatable接口中使用。
C#
public bool Equals(PointStruct other)
{
return (this._X == other._X) && (this._Y == other._Y);
}
VB Public Overloads Function Equals(ByVal other As PointStruct) As Boolean _
Implements System.IEquatable(Of PointStruct).Equals
Return m_X = other.m_X AndAlso m_Y = other.m_Y
End Function
对于类,需要额外检查空值。按照惯例,所有非空值被认为与空值不相等。
你会注意到我们没有使用地道的C#代码来检查空值。这是由于C#和VB处理相等性的方式有一处不同。
Visual Basic在处理引用相等和值相等上有明确的区别。前者使用Is擦作符,后者使用=操作符。
C#缺乏这种区别,对两者都使用==操作符。由于我们会重写==操作符,所以不想使用 ==,不得不转而使用一个后门。这个后门是Object.ReferenceEquals方法。
由于类总是与自己相等,所以在进行潜在的更昂贵的相等性检查之前,我们首先作这个检查。在下面代码中我们比较了私有成员变量,也可以使用属性来作比较。
C#
public bool Equals(PointClass other)
{
if (Object.ReferenceEquals(other, null))
{
return false;
}
if (Object.ReferenceEquals(other, this))
{
return true;
}
return (this._X == other._X) && (this._Y == other._Y);
}
VB
Public Overloads Function Equals(ByVal other As PointClass) As Boolean
Implements System.IEquatable(Of PointClass).Equals
If other Is Nothing Then Return False
If other Is Me Then Return True
Return m_X = other.m_X AndAlso m_Y = other.m_Y
End Function
下一步是产生哈希码。最简单的方法是将所有用于相等性比较的成员变量的哈希码作异或运算。
C#
public override int GetHashCode()
{
return _X.GetHashCode() ^ _Y.GetHashCode();
}
VB
Public Overrides Function GetHashCode() As Integer
Return m_X.GetHashCode Xor m_Y.GetHashCode
End Function
如果你确实决定要从头写自己的哈希码,你必须确保对于一套给定的值,你总是能返回相同的哈希码。换言之,如果a等于b,那么它们的哈希码也相等。
哈希码不必是唯一的,不同的值可以有相同的哈希码。但是它们应该有一个良好的分布。对于每一个哈希码都返回42在技术上是合法的,但是任何使用该算法的应用在性能上都会很糟糕。
哈希码应该以非常快的速度计算出来。由于计算哈希值可能成为瓶颈,所以宁可选用一个快速的有合理良好分布的哈希码算法,而不选择一个慢的,复杂的有着完美的均匀分布的算法。
重写基类的Equals方法是一个基础工作,该方法被Object.Equals(Object, Object)函数和其他方法调用。
你应该注意到由于类型转换做了两次,所以可能存在一点性能问题:一次是看它是否有效,第二次是真正的执行它。不幸的是,在结构中是无法避免这样作的。
C#
public override bool Equals(object obj)
{
if (obj is PointStruct)
{
return this.Equals((PointStruct)obj);
}
return false;
}
VB
Public Overrides Function Equals(ByVal obj As Object) As Boolean
If TypeOf obj Is PointStruct Then Return CType(obj, PointStruct) = Me
End Function
对于类可以只用一次类型转换。在处理步骤中,我们可以早点检测空值然后跳过对Equals(PointClass)方法的调用。C#必须用ReferenceEquals函数来检查空值。
为了防止子类破坏相等性,我们封闭(Seal)了方法。
C#
public sealed override bool Equals(object obj)
{
var temp = obj as PointClass;
if (!Object.ReferenceEquals(temp, null))
{
return this.Equals(temp);
}
return false;
}
VB
Public NotOverridable Overrides Function Equals(ByVal obj As Object) As Boolean
Dim temp = TryCast(obj, PointClass)
If temp IsNot Nothing Then Return Me.Equals(temp)
End Function
所有的难题都被攻克了,我们现在可以进行操作符的重写了。这里和调用类型安全的Equlas方法一样简单。
C#
public static bool operator ==(PointStruct point1 PointStruct point2)
{
return point1.Equals(point2);
}
public static bool operator !=(PointStruct point1, PointStruct point2)
{
return !(point1 == point2);
}
VB
Public Shared Operator =(ByVal point1 As PointStruct, ByVal point2 As PointStruct) As Boolean
Return point1.Equals(point2)
End Operator
Public Shared Operator <>(ByVal point1 As PointStruct,
ByVal point2 As PointStruct) As Boolean
Return Not (point1 = point2)
End Operator
对于类,需要检查空值。幸运的是,Object.Equals(object, object)为你处理了这种情况。然后调用已经被重写的Object.Equals(Object)方法。
C#
public static bool operator ==(PointClass point1, PointClass point2)
{
return Object.Equals(point1, point2);
}
public static bool operator !=(PointClass point1, PointClass point2)
{
return !(point1 == point2);
}
VB
Public Shared Operator =(ByVal point1 As PointClass, ByVal point2 As PointClass) As Boolean
Return Object.Equals(point1 ,point2)
End Operator
Public Shared Operator <>(ByVal point1 As PointClass, ByVal point2 As PointClass) As Boolean
Return Not (point1 = point2)
End Operator
你会注意到每个调用链都有点长,尤其是不相等操作符。如果需要考虑性能问题,你可以分别在每个方法中实现比较逻辑来提高速度。这样很容易出错而且使得维护工作比较辣手,所以仅仅当你使用性能检测工具证明了必须这样作之后,才应该这样作。
本文使用了下面的测试。它使用了列表的形式使得你可以方便的将它们翻译到你最喜欢的单元测试框架中。因为相等性很容易被破坏,所以这是单元测试的首要的测试目标。
请注意测试不是全面的。你应该测试左右值部分相等的情况,例如PointStruct(1, 2) and PointStruct(1, 5)。
| Variable | Type | Value |
|---|---|---|
| A | PointStruct | new PointStruct(1, 2) |
| a2 | PointStruct | new PointStruct(1, 2) |
| B | PointStruct | new PointStruct(3, 4) |
| nullValue | Object | Null |
| Expression | Expected Value |
|---|---|
|
Equal values
|
|
| a == a2 | True |
| a != a2 | False |
| a.Equals(a2) | True |
| object.Equals(a, a2) | True |
|
Unequal values, a on left
|
|
| b == a | False |
| b != a | True |
| b.Equals(a) | False |
| object.Equals(b, a) | False |
|
Unequal values, a on right
|
|
| a == b | False |
| a != b | True |
| a.Equals(b) | False |
| object.Equals(a, b) | False |
|
nulls, a on left
|
|
| a.Equals(nullValue) | False |
| object.Equals(a, nullValue) | False |
|
nulls, a on right
|
|
| object.Equals(nullValue, a) | False |
|
Hash codes
|
|
| a.GetHashCode() == a2.GetHashCode() | True |
| a.GetHashCode() == b.GetHashCode() | Indeterminate |
| Variable | Type | Value |
|---|---|---|
| a | PointClass | new PointClass (1, 2) |
| a2 | PointClass | new PointClass (1, 2) |
| b | PointClass | new PointClass (3,4) |
| nullValue | PointClass | Null |
| nullValue2 | PointClass | Null |
| Expression | Expected Value |
|---|---|
| Same Object | |
| a == a | True |
| a != a | False |
| a.Equals(a) | True |
| object.Equals(a, a) | True |
|
Equal values
|
|
| a == a2 | True |
| a != a2 | False |
| a.Equals(a2) | True |
| object.Equals(a, a2) | True |
|
Unequal values, a on left
|
|
| b == a | False |
| b != a | True |
| b.Equals(a) | False |
| object.Equals(b, a) | False |
|
Unequal values, a on right
|
|
| a == b | False |
| a != b | True |
| a.Equals(b) | False |
| object.Equals(a, b) | False |
|
nulls, a on left
|
|
| a == nullValue | False |
| a != nullValue | True |
| a.Equals(nullValue) | False |
| object.Equals(a, nullValue) | False |
|
nulls, a on right
|
|
| nullValue == a | False |
| nullValue != a | True |
| object.Equals(nullValue, a) | False |
|
both null
|
|
| nullValue == nullValue2 | True |
| object.Equals(nullValue, nullValue2) | True |
|
Hash codes
|
|
| a.GetHashCode() == a2.GetHashCode() | True |
| a.GetHashCode() == b.GetHashCode() | Indeterminate |
阅读英文原文:A Detailed look at Overriding the Equality Operator
本次分享将会就大规模视频网站的计费与流量管理这个话题,从操作层面细细进行讲解和分析,为系统工程师们揭示平日里我们没有关心的另一些内容。同时也希望本次分享能揭示行业中的一些“潜规则”,让互联网行业的流量与带宽管理更为开放与简洁。
本次演讲视频录制于QCon杭州2011。
Jeffrey Richter以其多本Windows核心技术的经典著作而闻名,同时,他深入掌握微软的.NET等一系列核心技术,2012年1月,Jeffrey Richter在北京接受了InfoQ中文站的专访,谈到Windows 8和WinRT编程,并就异步编程、Windows编程中的可扩展性、性能和安全性方面给出自己的建议。
云计算平台的可用性,相比传统互联网服务而言,更加复杂和困难,也更具有挑战性。本文借助新浪SAE云平台为读者讲述了云平台可用性的定义、如何打造高可用的平台,以及对云计算的用户提出了建议。
淘宝高度重视Java平台的健康发展,组建了一个团队专注于Java平台的底层部分的性能、功能与稳定性改进;工作主要基于OpenJDK中的HotSpot VM开展,其中一些通用的功能随后也会逐渐反馈给OpenJDK社区。希望能与使用Java平台开发应用的大家交流经验。
本次演讲视频录制于QCon杭州2011。
2011年4月21日至22日是值得云计算从业者纪念的日子。Amazon的IaaS服务出现故障,导致许多商业网站的服务中断,影响非常严重。作为云计算用户,我们需要思考的是,如何保证即便在云服务不可用的情况,我们的应用架构仍然能够屹立不倒?本文正是站在云计算用户的角度试图探讨这一问题。
12人的技术团队,4组刀片服务器,每月20亿的访问量,每日1次准时部署,99.9%的可用性。这可能吗?当然。想知道如何做的吗?百姓网将与您分享他们在DevOps实践过程中的经验和技巧。
本次演讲视频录制于QCon杭州2011。
篱笆作为一家起源于社区的电子商务公司,反映到技术层面就是同时要面对产品和业务,以及经营战略的变化调整。如何在产品和业务的夹缝之间完成技术架构的抽象与平衡,寻找更有效的价值定位,这当中有些经验教训和个人感悟愿与众人分享。
本次演讲视频录制于QCon杭州2011。
本文将对特性注入以及相关方法做一个扫盲性的介绍。我们会解释这个框架的关键要素,并附上实例来证实它们。为了让文章保持相对较短,我们不会深入到某个工具或方法中,而是会给出一些参考资料,以便大家做进一步的研究。
没有回复
关注此讨论 回复