多线程原理是啥?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多线程原理是啥?相关的知识,希望对你有一定的参考价值。
线程可以理解为下载的通道,一个线程就是一个文件的下载通道,多线程也就是同时开起好几个下载通道.当服务器提供下载服务时,使用下载者是共享带宽的,在优先级相同的情况下,总服务器会对总下载线程进行平均分配.不难理解,如果你线程多的话,那下载的越快.现流行的下载软件都支持多线程.. 注:实现多线程的条件是服务器支持,不支持的话……就用"用代理下载"[编辑本段]原理
多线程下载的原理是这样的:通常服务器同时与多个用户连接,用户之间共享带宽。如果N个用户的优先级都相同,那么每个用户连接到该服务器上的实际带宽就是服务器带宽的N分之一。可以想象,如果用户数目较多,则每个用户只能占有可怜的一点带宽,下载将会是个漫长的过程。 如果你通过多个线程同时与服务器连接,那么你就可以榨取到较高的带宽了。例如原来有10个用户都通过单一线程与服务器相连,服务器的总带宽假设为56Kbps,则每个用户(每个线程)分到的带宽是5.6Kbps,即0.7K字节/秒。如果你同时打开两个线程与服务器连接,那么共有11个线程与服务器连接,而你获得的带宽将是56/11*2=10.2Kbps,约1.27K字节/秒,将近原来的两倍。你同时打开的线程越多,你所获取的带宽就越大(原来是这样,以后每次我都通过1K个线程连接:P)。当然,这种情况下占用的机器资源也越多。有些号称“疯狂下载”的下载工具甚至可以同时打开100个线程连接服务器。 参考技术A 线程是一个操作系统概念。操作系统负责这个线程的创建、挂起、运行、阻塞和终结操作。而操作系统创建线程、切换线程状态、终结线程都要进行CPU调度——这是一个耗费时间和系统资源的事情。 参考技术B 你玩过打地鼠吗?那就是多线程。 参考技术C 多线程概述
进程和线程都是操作系统的概念。进程是应用程序的执行实例,每个进程是由私有的虚拟地址空间、代码、数据和其它各种系统资源组成,进程在运行过程中创建的资源随着进程的终止而被销毁,所使用的系统资源在进程终止时被释放或关闭。
线程是进程内部的一个执行单元。系统创建好进程后,实际上就启动执行了该进程的主执行线程,主执行线程以函数地址形式,比如说main或WinMain函数,将程序的启动点提供给Windows系统。主执行线程终止了,进程也就随之终止。
每一个进程至少有一个主执行线程,它无需由用户去主动创建,是由系统自动创建的。用户根据需要在应用程序中创建其它线程,多个线程并发地运行于同一个进程中。每个线程具有自己的堆栈和自己的 CPU 寄存器副本。其他资源(如文件、静态数据和堆内存)由进程中的所有线程共享。所以线程间的通讯非常方便,多线程技术的应用也较为广泛。但是使用这些公共资源的线程必须同步。Win32 提供了几种同步资源的方式,包括信号、临界区、事件和互斥体。
每个进程都有私有的虚拟地址空间,进程的所有线程共享同一地址空间。每个线程被CPU分配一个时间片,一旦被激活,它正常运行直到时间片耗尽并被挂起,此时,操作系统选择另一个线程进行运行。通过时间片轮转,又出于各个时间片很小(20毫秒级),看起来就像多个线程同时在工作。实际上,只有在多处理器系统上才是真正的在可得到的处理器上同时运行多个线程。基于Win32的应用程序可以通过把给定进程分解(或创建)多个线程挖掘潜在的CPU时间,而且还可以加强应用程序,以使用户提高效率,加强反应能力以及进行后台辅助处理。
在Windows操作系统中,Win32应用程序可以在Windows平台上运行多个实例,每个应用程序实例都是一个独立的进程,而一个进程可以由不止一个线程来实现。对于一个进程来说,当应用程序有几个任务要同时运行时,建立多个线程是有用的。如打印时,利用多线程机制实现多线程,就可在需要打印时创建一个负责完成打印功能的打印线程。创建打印线程之后,系统就变成了多线程。当进行打印时,CPU轮换着分配给这两个线程时间片,所以打印和其他功能一起同时在运行,这就充分利用了CPU处理打印工作之外的空闲时间片,并且避免了用户长久地等待打印时间。这就是所谓的由多线程来实现的多任务,在进行打印任务的同时又可以进行别的任务。要说明的一点是,目前大多数的计算机都是单处理器(CPU)的,为了运行所有这些线程,操作系统为每个独立线程安排一些CPU时间,操作系统以轮换方式向线程提供时间片,这就给人一种假象,好象这些线程都在同时运行。由此可见,如果两个非常活跃的线程为了抢夺对CPU的控制权,在线程切换时会消耗很多的CPU资源,反而会降低系统的性能。这一点在多线程编程时应该注意。
Win32 SDK函数支持进行多线程的程序设计,并提供了操作系统原理中的各种同步、互斥和临界区等操作。Visual C++ 6.0中,使用MFC类库也实现了多线程的程序设计,线程被分为工作者线程(Worker Thread)和用户界面线程(User Interface Thread)两大类。前者常用于处理后台任务,执行这些后台任务并不会耽搁用户对应用程序的使用,即用户操作无需等待后台任务的完成。后者常用来独立的处理用户输入和相应用户的事件。其中用户界面线程的特点是拥有单独的消息队列,可以具有自己的窗口界面,能够对用户输入和事件做出响应。在应用程序中,根据用户界面线程具有消息队列这一特点,可以使之循环等待某一事件发生后再进行处理。由于Windows95时抢先式多任务的操作系统,即使一个线程因等待某事件而阻塞,其他线程仍然可以继续执行。
处理 UIActivityIndicator 和多线程的最佳方法是啥?
【中文标题】处理 UIActivityIndicator 和多线程的最佳方法是啥?【英文标题】:What is the best way to deal with UIActivityIndicator and multiple threads?处理 UIActivityIndicator 和多线程的最佳方法是什么? 【发布时间】:2010-11-22 16:13:11 【问题描述】:我已经尝试了很长时间,但似乎找不到最佳方法。我很困惑,因为对于如何完成这个看似简单的任务似乎有不同的答案/意见。
我希望能够拥有一个名为 ActivityIndicatorController 的可重用类。该控制器有两个主要方法:activateIndicator 和 deactivateIndicator。它需要一个 UIView 作为参数/属性以及一个标签的 NSString。激活后,它将关闭 UIView 中的用户交互并添加一个矩形子视图(带有 alpha 和圆角)、一个 UIActivityIndicator 控件和一个用于状态文本的 UILabel。这是可取的,因为这样我不必在每个视图控制器中都有自定义 UIActivityIndicatorView 代码,也不必在每个 NIB 中设置 ActivityIndicator。
我遇到的根本问题是如何启动添加和动画化 ActivityIndicator 的过程。我尝试过的一些方法根本不显示新视图。其他人工作,但 ActivityIndicator 没有动画。
我曾尝试在 activateIndicator 方法中使用 [NSThread detachNewThreadSelector:@selector(startAnimating) toTarget:activityIndicator withObject:nil],但这不会显示新的 UIView。
我曾尝试在调用方法中使用 [NSThread detachNewThreadSelector:@selector(activateIndicator) toTarget:activityIndicatorController withObject:nil],但这会将新 UIView 的整个创建放在一个单独的线程中。
现在问题来了:
第 1 部分:我知道所有 UI 都应该在主线程上处理,对吗?
第 2 部分:使用 [NSThread detachThreadSelector] 与 NSOperation 有什么区别/优点/缺点?
第 3 部分:是否更好:
(a) 将冗长的操作发送到一个新的后台线程,并回调主线程或
(b) 将 UIActivityIndicatorView 的 startAnimating 方法发送到单独的线程并在主线程上运行冗长的进程
为什么?
这是我当前的代码:
ActivityViewController 类:
-(void)activateIndicator
NSLog(@"activateIndicator called");
if (isActivated || !delegateView)
return;
NSLog(@"activateIndicator started");
[delegateView.view setUserInteractionEnabled:NO];
[delegateView.navigationController.view setUserInteractionEnabled:NO];
[delegateView.tabBarController.view setUserInteractionEnabled:NO];
float w = [[UIScreen mainScreen] bounds].size.width;
float h = [[UIScreen mainScreen] bounds].size.height;
NSLog(@"Width = %f\nHeight = %f", w, h);
if (!disabledView)
disabledView = [[[UIView alloc] initWithFrame:CGRectMake((w - kNormalWidth) / 2.0, (h - kNormalHeight) / 2.0, kNormalWidth, kNormalHeight)] autorelease];
disabledView.center = [[[delegateView.view superview] superview] center];
[disabledView setBackgroundColor:[UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.85]];
CALayer *layer = [disabledView layer];
NSLog(@"layer=%@",layer);
NSLog(@"delegate=%@",[layer delegate]);
layer.cornerRadius = 12.0f;
if (!activityIndicator)
activityIndicator = [[[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(kNormalWidth / 2, 10.0f, 40.0f, 40.0f)] autorelease];
[activityIndicator setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleWhiteLarge];
activityIndicator.center = disabledView.center;
if (!activityLabel)
activityLabel = [[[UILabel alloc] initWithFrame:CGRectMake(10.0f, 100.0f, kNormalWidth - 20, 38)] autorelease];
activityLabel.text = labelText;
activityLabel.textAlignment = UITextAlignmentCenter;
activityLabel.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.0f];
activityLabel.textColor = [UIColor colorWithWhite:1.0f alpha:1.0f];
activityLabel.center = disabledView.center;
[[[delegateView.view superview] superview] addSubview:disabledView];
[[[delegateView.view superview] superview] addSubview:activityIndicator];
[[[delegateView.view superview] superview] addSubview:activityLabel];
[NSThread detachNewThreadSelector:@selector(startAnimating) toTarget:activityIndicator withObject:nil];
从应用中的多个位置调用代码:
ActivityIndicatorController *aic = [[ActivityIndicatorController alloc] init];
aic.delegateView = self;
aic.labelText = @"Test...";
[aic activateIndicator];
//DO LENGTHY WORK ON MAIN THREAD
[aic deactivateIndicator];
[aic release], aic = nil;
【问题讨论】:
您可能想要实际添加您的代码;) 是的,我添加了它。我不得不从我的另一台机器上抓取它。 【参考方案1】:第 1 部分:我知道所有 UI 都应该在主线程上处理,对吗?
正确。
第 2 部分:使用 [NSThread detachThreadSelector] 与 NSOperation 有什么区别/优点/缺点?
NSOperation
是一个更高级别的接口,允许您对操作进行排队、创建多个相互依赖的操作等。在后台处理任务的其他选项是performSelectorOnMainThread:...
/performSelectorInBackground:...
和 Grand Central调度。
第 3 部分:是否更好:
(a) 将冗长的操作发送到一个新的后台线程,并回调主线程或
(b) 将 UIActivityIndicatorView 的 startAnimating 方法发送到单独的线程并在主线程上运行冗长的进程
由于问题 1 的答案,(a) 是您唯一的选择。
【讨论】:
那么我上面代码中的 startAnimating 方法呢?我是保持原样还是将其更改为这个? [activityIndicator startAnimating];知道调用方法将负责将所有冗长的工作转移到另一个线程吗?detachNewThreadSelector
绝对是错误的。您必须确保基本上整个 -activateIndicator
方法在主线程上执行,方法是让您的控制器将其推送到主线程上,或者在任何其他线程上引发调用代码调用的异常。 [NSThread isMainThread]
告诉你是否在主线程上。
所以,为了清楚起见,从您的回答和 Daniel Dickson 的回答看来,我应该执行以下操作: 1. 从主线程调用 activateIndicator。 2. 我可以使用 [NSThread isMainThread] 来确保仅从主线程调用 activateIndicator。 3. 然后,我可以使用 NSOperation 来启动这个漫长的过程。 4. 一旦这个冗长的过程完成,我可以使用 performSelectorOnMainThread 让它在主线程上使用回调。 5. 该回调将进行任何清理,然后调用 deactivateIndicator。对吗?
我会回答我自己的评论。这种方式看起来确实很好用。【参考方案2】:
将您的冗长工作放在一个单独的线程中,这样它就不会完全屏蔽 UI,以防您确实需要一些交互(比如取消操作)。然后,您的 ActivityIndicatorController 应该调用主线程来完成所有 UI 工作,例如:
@implementation ActivityIndicatorController
- (void)activateIndicator
[self performSelectorOnMainThread:@selector(activateOnMainThread)
withObject:nil
waitUntilDone:YES];
- (void)activateOnMainThread
// Do your actual UI stuff here.
// And similarly for the deactivate method.
【讨论】:
感谢您的回复。你说“在这里做你实际的 UI 工作”是指我现在在 activateIndicator 中的大部分代码应该移动到你的新方法 activateOnMainThread 吗? 另外,“startAnimating”是否会以与上述相同的方式或 [activityIndicator startAnimating] 的方式运行? 是的,将任何创建或修改视图的内容移至activateOnMainThread
。由于该方法将在主线程上运行,因此您可以直接调用 UIKit 方法,例如[activityIndicator startAnimating]
。【参考方案3】:
一旦显示和动画,即使主线程被阻塞,活动指示器也会继续动画。
但是,视图没有机会出现,因为运行循环尚未执行,因为等待冗长的操作。
所以我认为您需要的只是延迟为 0 的 performSelector:withObject:afterDelay
,因此您的冗长操作将在您的指示器可见后排队并执行。
【讨论】:
以上是关于多线程原理是啥?的主要内容,如果未能解决你的问题,请参考以下文章