您好、欢迎来到现金彩票网!
当前位置:2019欢乐棋牌 > 争用条件 >

托管线程处理的最佳做法

发布时间:2019-07-02 06:29 来源:未知 编辑:admin

  多线程编程需要在编程时倍加注意。对于多数任务,通过将执行请求以线程池线程的方式排队,可以降低复杂性。本主题将探讨更复杂的情形,比如协调多个线程的工作或处理造成阻止的线程。

  多线程编程解决了吞吐量和响应性问题,但引入此功能会带来新的问题:死锁和争用条件。

  当两个线程中的每一个线程都在试图锁定另外一个线程已锁定的资源时,就会发生死锁。其中任何一个线程都不能继续执行。

  托管线程处理类的许多方法都提供了超时设定,可帮您检测到死锁。例如,下面的代码试图获取对当前实例的锁定。如果在 300 毫秒内未能锁定,Monitor.TryEnter将返回false。

  争用条件是当程序的结果取决于两个或更多个线程中的哪一个先到达某一特定代码块时出现的一种 Bug。多次运行程序将产生不同的结果,而且给定的任何一次运行的结果都不可预知。

  争用条件的一个简单例子是递增一个字段。假定某个类有一个私有static字段(在 Visual Basic 中为Shared),每创建该类的一个实例时它都递增一次,使用的代码是objCt++;(C#) 或objCt += 1(Visual Basic)。此操作要求将objCt中的值加载到一个寄存器中,使该值递增,然后将其存储到objCt中。

  在多线程应用程序中,一个已加载并递增该值的线程可能会被另一个线程抢先,抢先的线程执行全部的三个步骤;当第一个线程继续执行并存储其值时,它改写objCt,但不考虑该值在它暂停执行期间已更改这一事实。

  这种争用条件通过使用Interlocked类的方法,如rement,即可轻松避免。若要了解在多个线程间同步数据的其他技巧,请参见为多线程处理同步数据。

  争用条件也可能会在同步多个线程的活动时发生。编写每一行代码,都必须考虑出现以下特殊情况时会发生什么情况,这里的特殊情况是指:一个线程在执行该行代码(或构成该行的任何机器指令)前,其他线程抢先执行了该代码。

  多线程编程技术能够解决单处理器计算机和多处理器计算机的诸多问题,单处理器计算机大多用来运行最终用户软件,多处理器计算机通常用作服务器。

  多线程编程为计算机用户提供了更好的响应能力,并且使用空闲时间处理后台任务。如果在单处理器计算机上使用多线程编程,那么:

  后台线程仅在主用户线程空闲时才执行。连续运行的前台线程将使后台线程得不到处理器时间。

  对一个线程调用Thread.Start方法时,此线程只有等到当前线程结束或被操作系统抢占后才会执行。

  出现争用条件的原因通常是,程序员未预见到一个线程可能会在一个难以控制的时刻被抢占这一事实,有时就会出现另一线程抢先使用代码块这种情况。

  多线程编程提供了更大的吞吐量。十个处理器可以完成一个处理器的十倍的工作量,不过,只有将任务分开并让十个处理器同时工作才行;线程为划分任务并利用额外的处理能力提供了一种方便的办法。如果在多处理器计算机上使用多线程编程,那么:

  当您对一个线程调用Thread.Start方法时,此线程可能会,也可能不会立即执行,具体取决于处理器数目和当前在等待执行的线程的数目。

  争用条件不仅可能因为线程被意外抢占而发生,还可能因为在不同的处理器上执行的两个线程在抢用同一代码块而发生。

  在类的类构造函数(C# 中的static构造函数、Visual Basic 中的Shared Sub New)完成运行之前,该类不会初始化。为防止对未初始化的类型执行代码,在类构造函数完成运行之前,公共语言运行库会禁止从其他线程到类的static成员(Visual Basic 中的Shared成员)的所有调用。

  例如,如果某个类构造函数启动了一个新线程,并且该线程过程调用了该类的static成员,则在该类构造函数完成之前,会一直禁止新线程。

  不要使用Thread.Abort终止其他线程。对另一个线程调用Abort无异于引发该线程的异常,也不知道该线程已处理到哪个位置。

  不要从主程序中控制辅助线程的执行(如使用事件),而应在设计程序时让辅助线程负责等待任务,执行任务,并在完成时通知程序的其他部分。如果辅助线程不阻止,请考虑使用线程池线程。Monitor.PulseAll在辅助线程阻止的情况下会很有用。

  锁定实例时要谨慎,例如,C# 中的lock(this)或 Visual Basic 中的SyncLock(Me)。如果您的应用程序中不属于该类型的其他代码锁定了该对象,则会发生死锁。

  一定要确保已进入监视器的线程始终离开该监视器,即使当线程在监视器中时发生异常也是如此。C# 的lock语句和 Visual Basic 的SyncLock语句可自动提供此行为,它们用一个finally块来确保调用Monitor.Exit。如果无法确保调用Exit,请考虑将您的设计更改为使用Mutex。Mutex 在当前拥有它的线程终止后会自动释放。

  一定要针对那些需要不同资源的任务使用多线程,避免向单个资源指定多个线程。例如,任何涉及 I/O 的任务都会从其拥有其自己的线程这一点得到好处,因为此线程在 I/O 操作期间将阻止,从而允许其他线程执行。用户输入是另一种可从专用线程获益的资源。在单处理器计算机上,涉及大量计算的任务可与用户输入和涉及 I/O 的任务并存,但多个计算量大的任务将相互竞争。

  对于简单的状态更改,请考虑使用Interlocked类的方法,而不是lock语句(在 Visual Basic 中为SyncLock)。lock语句是一个优秀的通用工具,但是Interlocked类为必须是原子性的更新提供了更好的性能。如果没有争夺,它会在内部执行一个锁定前缀。在查看代码时,请注意类似于以下示例所示的代码。在第一个示例中,状态变量是递增的:

  可以使用Increment方法代替lock语句,从而提高性能,如下所示:

  在第二个示例中,仅当引用类型变量为空引用(在 Visual Basic 中为Nothing)时,它才会被更新。

  在Framework 2.0 版中,CompareExchange方法具有一个泛型重载,可用于对任何引用类型进行类型安全的替换。

  如果可能,请避免同步需求。对于大量使用的代码更应如此。例如,可以将一个算法调整为容忍争用情况,而不是完全消除争用情况。不必要的同步会降低性能,并且可能导致出现死锁和争用情况。

  默认情况下使静态数据(在 Visual Basic 中为Shared)是线程安全的。

  默认情况下不要使实例数据是线程安全的。通过添加锁来创建线程安全的代码的做法会降低性能、加剧锁争夺,并且可能导致出现死锁。在常见的应用程序模型中,某一时刻只有一个线程执行用户代码,这样可以使对线程安全的需求变为最小。出于此原因,.NET Framework 类库默认情况下不是线程安全的。

  避免提供可更改静态状态的静态方法。在常见的服务器方案中,静态状态在各个请求之间是共享的,这意味着多个线程可在同一时刻执行该代码。这样就有可能出现线程错误。请考虑使用一种设计模式,将数据封装到在各请求之间不共享的实例中。此外,如果同步静态数据,更改状态的静态方法间的调用可导致死锁或冗余同步,从而降低性能。

  VS2003的帮助文档中有这样一篇《托管线程处理的最佳做法》rnrn其中提到:rnrn一般建议rnrn使用多线程时要考虑以下准则: rnrn 不要使用 Thread.Abort 终止其他线程。对另一个线程调用 Abort 无异于引发此线程的异常,而且将不知道此线程已处理到哪一点。 rn (需要终止线程时用什么方法?)rnrn 不要使用 Thread.Suspend 和 Thread.Resume 来同步多个线程的活动。不要使用 Mutex, ManualResetEvent、AutoResetEvent 和 Monitor。rn (哪还有什么方法来实现同步??) rnrn 不要从主程序中控制辅助程的执行,比如使用事件,而应在设计程序时让辅助线程负责等待任务,执行任务,并在完成时通知程序的其他部分。......rn (等待任务......怎样实现?)rnrnrn想好好学习一下的线程使用方法,不知哪里有好的实例或教程?论坛

  随着 J2EE 成为企业开发平台之选,越来越多基于 J2EE 的应用程序将投入生产。J2EE 平台的重要组件之一是 Enterprise JavaBean(EJB)API。J2EE 和 EJB 技术一起提供了许多优点,但随之而来的还有一些新的挑战。特别是企业系统,其中的任何问题都必须快速得到解决。在本文中,企业 Java 编程老手 Srikanth Shenoy 展现了他在 EJB 异常处理方面的最佳做法,这些做法可以更快解决问题。 rnrn 在 hello-world 情形中,异常处理非常简单。每当碰到某个方法的异常时,就捕获该异常并打印堆栈跟踪或者声明这个方法抛出异常。不幸的是,这种办法不足以处理现实中出现的各种类型的异常。在生产系统中,当有异常抛出时,很可能是最终用户无法处理他或她的请求。当发生这样的异常时,最终用户通常希望能这样: rnrn 有一条清楚的消息表明已经发生了一个错误 rnrn 有一个唯一的错误号,他可以据此访问可方便获得的客户支持系统 rnrn 问题快速得到解决,并且可以确信他的请求已经得到处理,或者将在设定的时间段内得到处理。 rnrn 理想情况下,企业级系统将不仅为客户提供这些基本的服务,还将准备好一些必要的后端机制。举例来说,客户服务小组应该收到即时的错误通知,以便在客户打电话求助之前服务代表就能意识到问题。此外,服务代表应该能够交叉引用用户的唯一错误号和产品日志,从而快速识别问题 — 最好是能把问题定位到确切的行号或确切的方法。为了给最终用户和支持小组提供他们需要的工具和服务,在构建一个系统时,您就必须对系统被部署后可能出问题的所有地方心中有数。 rnrn 在本文中,我们将谈谈基于 EJB 的系统中的异常处理。我们将从回顾异常处理的基础知识开始,包括日志实用程序的使用,然后,很快就转入对 EJB 技术如何定义和管理不同类型的异常进行更详细的讨论。此后,我们将通过一些代码示例来研究一些常见的异常处理解决方案的优缺点,我还将展示我自己在充分利用 EJB 异常处理方面的最佳做法。 rnrn 请注意,本文假设您熟悉 J2EE 和 EJB 技术。您应理解实体 bean 和会话 bean 的差异。如果您对 bean 管理的持久性(bean-managed persistence(BMP))和容器管理的持久性(container-managed persistence(CMP))在实体 bean 上下文中是什么意思稍有了解,也是有帮助的。请参阅参考资料部分了解关于 J2EE 和 EJB 技术的更多信息。 rnrn 异常处理基础知识 rnrn 解决系统错误的第一步是建立一个与生产系统具有相同构造的测试系统,然后跟踪导致抛出异常的所有代码,以及代码中的所有不同分支。在分布式应用程序中,很可能是调试器不工作了,所以,您可能将用 System.out.println() 方法跟踪异常。System.out.println 尽管很方便,但开销巨大。在磁盘 I/O 期间,System.out.println 对 I/O 处理进行同步,这极大降低了吞吐量。在缺省情况下,堆栈跟踪被记录到控制台。但是,在生产系统中,浏览控制台以查看异常跟踪是行不通的。而且,不能保证堆栈跟踪会显示在生产系统中,因为,在 NT 上,系统管理员可以把 System.out 和 System.err 映射到 ,在 UNIX 上,可以映射到 dev/null。此外,如果您把 J2EE 应用程序服务器作为 NT 服务运行,甚至不会有控制台。即使您把控制台日志重定向到一个输出文件,当产品 J2EE 应用程序服务器重新启动时,这个文件很可能也将被重写。 rnrn 异常处理的原则 rnrn 以下是一些普遍接受的异常处理原则: rn☆ 如果无法处理某个异常,那就不要捕获它。 rn☆ 如果捕获了一个异常,请不要胡乱处理它。 rn☆ 尽量在靠近异常被抛出的地方捕获异常。 rn☆ 在捕获异常的地方将它记录到日志中,除非您打算将它重新抛出。 rn☆ 按照您的异常处理必须多精细来构造您的方法。 rn☆ 需要用几种类型的异常就用几种,尤其是对于应用程序异常。 rnrn 第 1 点显然与第 3 点相抵触。实际的解决方案是以下两者的折衷:您在距异常被抛出多近的地方将它捕获;在完全丢失原始异常的意图或内容之前,您可以让异常落在多远的地方。 rnrn 注:尽管这些原则的应用遍及所有 EJB 异常处理机制,但它们并不是特别针对 EJB 异常处理的。 rnrn 由于以上这些原因,把代码组装成产品并同时包含 System.out.println 并不是一种选择。在测试期间使用 System.out.println,然后在形成产品之前除去 System.out.println 也不是上策,因为这样做意味着您的产品代码与测试代码运行得不尽相同。您需要的是一种声明控制日志机制,以使您的测试代码和产品代码相同,并且当记录日志以声明方式关闭时,给产品带来的性能开销最小。 rnrn 这里的解决方案显然是使用一个日志实用程序。采用恰当的编码约定,日志实用程序将负责精确地记录下任何类型的消息,不论是系统错误还是一些警告。所以,我们将在进一步讲述之前谈谈日志实用程序。 rnrn 日志领域:鸟瞰 rnrn 每个大型应用程序在开发、测试及产品周期中都使用日志实用程序。在今天的日志领域中,有几个角逐者,其中有两个广为人知。一个是 Log4J,它是来自 Apache 的 Jakarta 的一个开放源代码的项目。另一个是 J2SE 1.4 捆绑提供的,它是最近刚加入到这个行列的。我们将使用 Log4J 说明本文所讨论的最佳做法;但是,这些最佳做法并不特别依赖于 Log4J。 rnrn Log4J 有三个主要组件:layout、appender 和 category。Layou 代表消息被记录到日志中的格式。appender 是消息将被记录到的物理位置的别名。而 category 则是有名称的实体:您可以把它当作是日志的句柄。layout 和 appender 在 XML 配置文件中声明。每个 category 带有它自己的 layout 和 appender 定义。当您获取了一个 category 并把消息记录到它那里时,消息在与该 category 相关联的各个 appender 处结束,并且所有这些消息都将以 XML 配置文件中指定的 layout 格式表示。 rnrn Log4J 给消息指定四种优先级:它们是 ERROR、WARN、INFO 和 DEBUG。为便于本文的讨论,所有异常都以具有 ERROR 优先级记录。当记录本文中的一个异常时,我们将能够找到获取 category(使用 Category.getInstance(String name) 方法)的代码,然后调用方法 category.error()(它与具有 ERROR 优先级的消息相对应)。 rnrn 尽管日志实用程序能帮助我们把消息记录到适当的持久位置,但它们并不能根除问题。它们不能从产品日志中精确找出某个客户的问题报告;这一便利技术留给您把它构建到您正在开发的系统中。 rnrn 要了解关于 Log4J 日志实用程序或 J2SE 所带的日志实用程序的更多信息,请参阅参考资料部分。 rnrn 异常的类别 rnrn 异常的分类有不同方式。这里,我们将讨论从 EJB 的角度如何对异常进行分类。EJB 规范将异常大致分成三类: rnrn JVM 异常:这种类型的异常由 JVM 抛出。OutOfMemoryError 就是 JVM 异常的一个常见示例。对 JVM 异常您无能为力。它们表明一种致命的情况。唯一得体的退出办法是停止应用程序服务器(可能要增加硬件资源),然后重新启动系统。 rnrn 应用程序异常:应用程序异常是一种定制异常,由应用程序或第三方的库抛出。这些本质上是受查异常(checked exception);它们预示了业务逻辑中的某个条件尚未满足。在这样的情况下,EJB 方法的调用者可以得体地处理这种局面并采用另一条备用途径。 rn rn 系统异常:在大多数情况下,系统异常由 JVM 作为 RuntimeException 的子类抛出。例如,NullPointerException 或 ArrayOutOfBoundsException 将因代码中的错误而被抛出。另一种类型的系统异常在系统碰到配置不当的资源(例如,拼写错误的 JNDI 查找(JNDI lookup))时发生。在这种情况下,系统就将抛出一个受查异常。捕获这些受查系统异常并将它们作为非受查异常(unchecked exception)抛出颇有意义。最重要的规则是,如果您对某个异常无能为力,那么它就是一个系统异常并且应当作为非受查异常抛出。 rnrn 注:受查异常是一个作为g.Exception 的子类的 Java 类。通过从 java.lang.Exception 派生子类,就强制您在编译时捕获这个异常。相反地,非受查异常则是一个作为 java.lang.RuntimeException 的子类的 Java 类。从 java.lang.RuntimeException 派生子类确保了编译器不会强制您捕获这个异常。

  VS2015“检测到在集成的托管管道模式下不适用的 ASP.NET 设置”的最终解决办法

  Dell EMC Unity系列硬件安装指南官方中文手册,本人花钱购买的,内容绝对详实。

  ActionScript 2.0 的最佳做法和编码约定,一篇值得深入了解的图书!

  数据的机密性保护是一个老生常谈的问题,现在,又由于可移动存储设备、笔记本电脑和手持智能设备的大量使用,更进一步地加剧了企业机密数据的泄漏问题。由于企业机密数据的泄漏不仅会给企业带来经济和无形资产的损失...

  安全公司ESET和Sucuri的研究人员发现了最新针对Apache的高调攻击,攻击人员试图寻找一个后门进入Apache,重定向网络流量到恶意网站,访客进入恶意网站后,将被Blackhole漏洞利用工具包所感染 。这种攻击表明,企业必须制定...

  可根据您的需要,以多种方式对时态数据进行存储。以下是在存储时态数据以在ArcGIS中进行使用时可遵循的一些最佳做法。...

  [color=#FF0000]使用适当的命名约定[/color]rnrn你的代码的一致性,你应该更喜欢适当的命名约定。这是非常易于维护的代码,如果使用一致的命名所有的解决方案。下面是一些。NET开发人员一般都遵循命名约定:rn在声明变量的同时,一定要使用骆驼的情况下(A单词的首字母小写,后续的每一个字部分资本化的第一个字母)。rn使用帕斯卡(A单词的第一个字母大写,每个后续的文字部分资本化的第一个字母)命名格式,同时宣告属性。rn避免使用全部大写或小写的名称,属性,变量或方法名。声明const变量时,全部使用大写。rn切勿使用以数字字符开头的名称。rn总是喜欢有意义的名字,你的类,属性,方法等,为您维护的代码在未来,这将是非常有用的。例如,“P”不给一类的应有之义。你会发现它很难知道的类。但是,如果你使用了“人”,你会很容易地理解它。rn不要建立一个不同的名称,不同的资本化。这是一个非常糟糕的做法。这不会是有用的,而开发的代码,因为你不知道什么是“人”一类的,什么是“人”类!!但是,从上述情况下,它可以是非常容易理解的“人”是“人”类的实例变量。rn不要使用相同的名称。NET Framework中使用。人们谁是新的给你的代码有很大的困难,很容易理解。rn避免添加前缀或后缀的标识符。虽然在一些指引,他们使用“M_”和其他一些他们使用“_”作为前缀的变量声明。我认为这是没有那么多有用的。但是,这取决于您的组织的编码实践。这一点是矛盾的,基于各种组织,它是没有严格指导。rn始终使用“我”作为前缀的接口。用于定义界面,这是一个普遍的做法。rn一定要添加“例外”作为您的自定义异常类的后缀。这将提供更好的能见度到你的异常类。rn从来没有前缀或后缀的类名,属性名称。这将不必要地增加属性的名称。如果“ 姓 “是” 人 “类的属性,你可以很容易地识别它直接从这个类。没有需要到写“ PersonFirstname的 “或” FirstnameOfPerson“的。rn前缀“ 是 “,” 有 “或” 能 “布尔属性,如” IsVisible “,” HasChildren “,” CanExecute “。这些应有之义的属性。rn不要加前缀为您的控件,而不是写适当的名称,识别控制。rn值类型和引用类型之间做出选择rnrn当你需要创建一个类型,首先要问自己一个问题:“你想要什么,为什么你要吗?”。如果你能回答你的问题,你可以决定你要使用之间的类型。如果你想存储你的数据,使用值类型,当你想创建一个实例的类型定义的行为,使用引用类型。是不是多态,而值类型,引用类型可以是。值类型是最有效的引用类型的内存利用率,并产生更少的帮助碎片和垃圾。如果你想将值传递到一个方法的实现,决定你想要做什么,并根据您的要求,决定之间的值类型和引用类型。引用类型变量的使用,实际上改变了原来的价值,但使用值类型,将创建一个副本的原始变量,并通过在整个方法。因此,它可以保护你的原始值的意外改变。让我们来看看他们真实的例子。在下面的代码中,我们通过变量“ 我 “的价值类型和方法实现递增10。因为它是按值传递,你会看到原始值“ 5 “作为输出的程序代码。rnrn请务必使用属性而不是公共变量rnrn这背后的原因是,它,在OOPS环境使你的代码正确封装。通过使用getter和setter方法,您可以限制用户直接访问成员变量。您可以限制设定值明确从而使您的数据免受意外的变化。此外,物业让您更容易为您的数据验证。rnrn需要的时候使用可空数据类型rnrn有时候,你可能需要存储的一个整数,双或布尔变量的值,则返回null。所以你怎么能这样做呢?正常的声明并没有允许你存储的空值。C#现在可空数据类型的特点。在声明中只是一个小的变化。这就是它!你是好样去存储空值。只有你必须使用“?”修饰符。你必须把它放在刚刚结束的类型。要定义一个整数,你通常会做以下声明:rnrn不想运行时的常量在编译时间常数rnrn运行时的常量总是比编译时间常数的首选。在这里,你可能会问,什么是运行时不变的,什么是编译时间常数。运行时的常量是那些在运行时进行评估,并宣布与关键字“ 只读 “。在另一边,编译时间常数是静态的,在编译时评估,并宣布与关键字“ 常量 “rnrn喜欢的String.Format()或StringBuilder字符串连接rnrn是一个可变对象作为字符串,该字符串中的任何操作将创建一个新的对象。如果要连接多个字符串 s ,它始终是更好的String.Format()方法或串联的StringBuilder类的使用。rnrn正确利用的try / catch / finally块rnrn是的,妥善运用尝试 / 捕捉 / 最后块。如果你知道你写的代码可能会抛出一些异常,使用的try / 赶上这段代码块来处理异常。如果你知道,第五行10行代码可能会抛出异常,最好是只用“的尝试 / catch块来包装该行的代码。周围的几行代码,不必要的尝试 / 捕捉会减慢你的应用程序。有时候,我发现周围的人每一种方法的尝试 /catch块这实在是很糟糕,降低性能的代码。所以从现在开始,只在需要的时候使用。最后使用的块调用后清理的任何资源。如果你正在做的任何数据库调用,关闭连接在该块。最后块你的代码是否执行或不正确执行。因此,正确地利用它来 清除资源。rn只捕获该异常,你可以处理rnrn这是主要的一个。人们总是使用通用的异常类,捕捉任何异常,既不是为您的应用程序,也没有系统的性能。只捕获那些你期望并责令其相应。最后结束时,如果你想添加的通用异常捕捉任何其他的未知异常。这给你一个正确的方法来处理异常。假设,你的代码抛出NullReferenceException异常或ArgumentException。如果你直接使用的异常类,这将是非常困难的,在你的应用程序来处理。但是,的正确捕获异常,你可以处理的问题很容易。rn使用IDisposable接口rnrn使用IDisposable的接口从内存中释放所有的资源。一旦你在你的类中实现IDisposable接口的接口,你会得到一个的Dispose()方法有。编写代码来释放资源。如果你实现了IDisposable接口,你可以初始化你的类是这样的:rn

  视频播放器做法视频播放器做法视频播放器做法视频播放器做法视频播放器做法视频播放器做法视频播放器做法视频播放器做法视频播放器做法视频播放器做法视频播放器做法

  为了可以拨号上网在Ubuntu上安装了dsl-provider,安装完成后发现有线网无法使用,只能使用无线网.有线连接一直提示”有线未托管”.查阅资料后发现造成问题的原因:Linux里面有两套管理网络...

  机器学习教程Objective-C培训交互设计视频教程颜色模型设计制作学习

  微信小程序的云函数本地调用及调试方法weixin_42904637:有那两个key怎么调试?没看懂

  wangjuxiang1996:我想请教一下, 在vivado上我想把三个模块的程序组合到一个模块中烧到开发板上,该怎么操作呢?希望得到您的回复

  Xzzzz3:您好 我在做一个环境 请问您知道这个算法中的n_feature表示的是什么意思吗 在其他的环境里这个应该是哪种东西来表示呢?

http://altofigaro.com/zhengyongtiaojian/105.html
锟斤拷锟斤拷锟斤拷QQ微锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷微锟斤拷
关于我们|联系我们|版权声明|网站地图|
Copyright © 2002-2019 现金彩票 版权所有