-
2019-05-30 18:18:56
前言:
面试官:多线程和单线程哪个快?
我凭借微弱的记忆以及正经分析回答:多线程快,因为可以执行多个任务,而单线程只能执行一个任务。
面试官:无论什么情况多线程都比单线程快吗?
我犹豫了一下正经回答:不是的,线程执行消耗的是cpu的,cpu资源是有限的,所有不是一直比单线程快。
面试官:那什么情况下单线程比多线程快?
我…:这…不清楚。
面试官:你没有学过《计算机基础》吗?你已经自相矛盾了…
我:没学过,好吧,我不知道。
后来这个面试官变成了我的老大,技术总监,进公司第一天下午讨论某问题之后单独叫我谈话。
老大问我那个问题有没有去了解过。
我虚了:我看了,不一定,多线程存在上下文切换。
老大:多线程一定比单线程慢,上下文切换你知道什么意思吗?
我心想完了:额…看了忘记了。
然后噼里啪啦跟我解释,我现在依旧忘记了…正文:
回家后我再次查阅资料:
首先分配cpu资源的单位是进程。一个进程所获得到的cpu资源是一定的。程序在执行的过程中消耗的是cpu,比如一个单核cpu,多个线程同时执行工作时,需要不断切换执行(上下文切换),单个线程时间耗费更多了,而单线程只是一个线程跑。
比如:
处理10个报表,
在单线程的情况下,假如说我们生成10个报表文件需要1个小时。
单线程是先执行完第一个报表,用了6分钟,再执行第二个报表,也用6分钟。总计1个小时
多线程,是10个报表一起执行,但是每一个报表都要1个小时。
总结:多线程的总体执行时间和单线程是一样的,但是多线程中单个线程的执行时间是单线程的多倍。
多线程提高的是并发数量,比如现在有一个4核cpu的服务器,同一时间可执行4个线程,这样处理线程任务的速度比较快。但是多出来的线程,5个,6个,7个,多出的线程还是要等待。上下文切换
多线程编程中一般线程的个数都大于 CPU 核心的个数,而一个 CPU 核心在任意时刻只能被一个线程使用,为了让这些线程都能得到有效执行,CPU 采取的策略是为每个线程分配时间片并轮转的形式。当一个线程的时间片用完的时候就会重新处于就绪状态让给其他线程使用,这个过程就属于一次上下文切换。概括来说就是:当前任务在执行完 CPU 时间片切换到另一个任务之前会先保存自己的状态,以便下次再切换会这个任务时,可以再加载这个任务的状态。任务从保存到再加载的过程就是一次上下文切换。
后记:
基础不牢固的情况下去回答问题是非常容易打脸的,回答出的答案也是稀里糊涂的,稍微换个角度攻击就会一脸懵逼,学习更多的新技术其实没太大用处,因为这个行业技术迭代的很快,基础才是永久的饭碗,所以我决定从java虚拟机开始入手,修炼内功,找对方向获得会更多!
更多相关内容 -
python日记(一):为什么我的多线程速度反而不如单线程?
2021-01-20 02:05:57然后就动手写了一个多线程,但是发现速度甚至不及单线程,甚至还要更慢。Excuse Me???? 然后就去查看了一下别的大佬怎么讲。 python线程原理(敲黑板) 下面引入一个概念GIL。我们看官方给出的解释: In CPython... -
【java多线程】多线程为什么跑的比单线程还要慢?!
2018-12-15 11:34:54问:多线程是不是能加快处理速度?...假设我要拷贝100万条数据,单CPU电脑,用一个进程,在单线程的情况下,CPU占用率为5%,耗时1000秒。那么当在这个进程下,开辟10个线程同时去运行,是不是CPU占用...问:多线程是不是能加快处理速度?
解析:
在使用多线程时,一定要知道一个道理:处理速度的最终决定因素是CPU、内存等,在单CPU(无论多少核)上,分配CPU资源的单位是“进程”而不是“线程”。
我们可以做一个简单的试验:
假设我要拷贝100万条数据,单CPU电脑,用一个进程,在单线程的情况下,CPU占用率为5%,耗时1000秒。那么当在这个进程下,开辟10个线程同时去运行,是不是CPU占用率增加到50%,耗时减少到100秒呢?显然不是。我实测出来的情况是这样的:
“CPU占用率仍然是5%,总耗时仍然是1000秒。且每个线程的运行时间也为1000秒。”
重点是后面那句,怎么理解?意味着什么?
我的理解如下:进程只有一个,所以分配的CPU资源是一定的,多线程只不过是轮流抢占CPU而已,并不会真正提高处理速度。这意味着,多线程的作用主要在于提高了并发数量,比如http请求,如果是单线程,一次只能接收一个请求,多线程则可以同时接收多个请求。
但是多线程由于轮换使用CPU,会造成单个线程的执行速度变慢(以前CPU供一个线程使用,现在要供多个线程轮流使用了)。但是在多CPU的服务器上,多线程就很有优势了,它不但能提高并发数量,而且能提高处理速度。因为在多CPU的服务器上,CPU调度很灵活,当一个线程占用着一个CPU的时候,其他线程可以被分配给其他CPU去处理,从而实现了“真正意义上地并行”。
总结:
第一,看硬件。如果是在比较强大的、多CPU的服务器上运行程序,可以使用多线程来提高并发数和执行速度。但是线程也不宜过多,即使是16个CPU的服务器,同一时间最多也只能真正意义上地并发处理16个线程,多出来的线程还是要等待。
第二,看用途。如果你不在乎处理速度,仅仅是为了提高并发处理能力,那么理所当然地用多线程,但是如果你仅仅是想提高处理速度,且又是在单CPU机器上运行,那么多线程并不值得。如果你的任务很耗时,且可以一部分、一部分地做,那么最好不要用多线程(好比搬砖,单线程一次搬10块,总共搬10天,但搬一块算一块,到第9天的时候,你就搬完90块砖了;如果你用10个线程同时去搬砖,同样要搬10天,但是到第9天的时候,这10个线程100块砖都“还在路上”,一块砖都没搬完!)。
一个实际例子
在单线程的情况下,假如说我们生成10个报表文件需要1个小时。
如果是在多线程的情况下呢,生成10个文件要多少个小时?
同样要1个小时。不管你有多少个线程,就算你有100个线程,一样需要1个小时。
这就是问题所在。单线程和多线程的区别在哪里?
单线程是先执行完第一个报表,用了6分钟,再执行第二个报表,也用6分钟。
多线程,是10个报表一起执行,但是每一个报表都要1个小时。
同一个线程,比如说一个servlet,一个人去访问,执行它,只需要2秒。
如果两个人同时去访问,可能就要4秒。如果10个人同时去访问,那么每个人就要
等待20秒。就是说它基本上是一个成倍的线性增长。
一个线程占2%的CPU,那是不是50个线程就占100%的CPU?不是。
50个线程仍然占2%的CPU,分配CPU资源的单位是进程,而不是线程。
所以说线程是无法加快执行速度的
多线程的总体执行时间和单线程是一样的,但是多线程单个线程的执行时间
是单线程的多倍。
我这里有一组数据,我有两个任务,如果是单线程。
先执行任务1,再执行任务2,一共用了80秒钟,每个任务花费40秒
如果我用2个线程同时跑,一共也用了80秒,但是每个任务都花费80秒(也就是说在最后一刻的时候,两个任务几乎是同时完成)。
附:以下两组数据是单线程和多线程耗时的对比(win7系统、笔记本i7 CPU)。
单位:毫秒
编号
单线程1
单线程2
2个线程同时运行
测试1
81284
81020
155373
测试2
79601
78405
154144
从上面数据可见,2个线程同时运行的时间,几乎等于线程1+线程2单独运行的时间。所以说多线程实际上总时间没变,但是单个任务的执行时间延长了。
我的测试:
463600条数据模拟银行账户转账:
线程数 结果 时间 1 8118ms 100 15011ms 200 12665ms
400 13533ms 使用的数据:10 25 2500:表示将2500元从账号10转到了账号25。
代码 下载地址:https://download.csdn.net/download/qq_36396104/10852122
-
python多线程比单线程效率低的原因及其解决办法
2021-06-10 20:35:15python多线程比单线程效率低的原因是:GIL python中有一个 GIL( Global Interpreter Lock),中文为:全局解释器锁 - 最开始时候设计GIL是为了数据安全。python为了数据安全设计了这个 GIL - 每个 CPU在同一时间...前言
Python语言的标准实现叫作CPython,它分两步来运行Python程序
- 步骤1:解析源代码文本,并将其编译成字节码(bytecode)
- 字节码是一种底层代码,可以把程序表示成8位的指令
- 从Python 3.6开始,这种底层代码实际上已经变成16位了
- 步骤2:CPython采用基于栈的解释器来运行字节码。
- 字节码解释器在执行Python程序的过程中,必须确保相关的状态不受干扰,
- CPython会用一种叫作全局解释器锁(global interpreter lock,GIL)的机制来实现运行的python程序的相关状态不受干扰
GIL
- GIL实际上就是一种互斥锁(mutual-exclusion lock,mutex),用来防止CPython的状态在抢占式的多线程环境(preemptive multithreading)之中受到干扰,因为在这种环境下,一条线程有可能突然打断另一条线程抢占程序的控制权。如果这种抢占行为来得不是时候,那么解释器的状态(例如为垃圾回收工作而设立的引用计数等)就会遭到破坏。
- CPython要通过GIL阻止这样的动作,以确保它自身以及它的那些C扩展模块能够正确地执行每一条字节码指令。
- GIL会产生一个很不好的影响。在C++与Java这样的语言里面,如果程序之中有多个线程能够分头执行任务,那么就可以把CPU的各个核心充分地利用起来。尽管Python也支持多线程,但这些线程受GIL约束,所以每次或许只能有一条线程向前推进,而无法实现多头并进。
- 所以,想通过多线程做并行计算或是给程序提速的开发者,恐怕要失望了。
- 并发 concurrency : 指计算机似乎能在同一时刻做许多不同的事情
- 并行 parallelism : 指计算机确实能够在同一时刻做许多不同的事情
多线程下的线程执行
- 获取GIL
- 执行代码直到sleep或者是 python虚拟机将其挂起。
- 释放 GIL
多线程效率低于单线程原因
- 如上我们可以知道,在 python中想要某个线程要执行必须先拿到 GIL这把锁,且 python只有一个 GIL,拿到这个 GIL才能进入 CPU执行, 在遇到 I/O操作时会释放这把锁。如果是纯计算的程序,没有 I/O 操作,解释器会每隔 100次操作就释放这把锁,让别的线程有机会 执行(这个次数可以通sys.setcheckinterval来调整)。所以虽然 CPython 的线程库直接封装操作系统的原生线程,但 CPython 进程做为一个整体,同一时间只会有一个获得了 GIL 的线程在跑,其它的线程都处于等待状态等着 GIL 的释放。
- 而每次释放 GIL锁,线程进行锁竞争、切换线程,会消耗资源。并且由于 GIL锁存在,python里一个进程永远只能同时执行一个线程 (拿到 GIL的线程才能执行 ),这就是为什么在多核 CPU上, python的多线程效率并不高
多线程效率低于或高于单线程原因
- 相同的代码,为何有时候多线程会比单线程慢,有时又会比单线程快? 这主要跟运行的代码有关:
- CPU密集型代码(各种循环处理、计数等等 ),在这种情况下,由于计算工作多, ticks计数很快就会达到 100阈值,然后触发 GIL的释放与再竞争 (多个线程来回切换当然是需要消耗资源的),所以 python下的多线程遇到 CPU密集型代码时,单线程比多线程效率高。
- IO密集型代码 (文件处理、网络爬虫等 ),多线程能够有效提升效率单线程下有 IO操作会进行 IO等待,造成不必要的时间浪费。开启多线程能在线程 A等待时,自动切换到线程 B,可以不浪费 CPU的资源,从而能提升程序执行效率 。进行IO密集型的时候可以进行分时切换 所有这个时候多线程快过单线程
如果 python想充分利用多核 CPU,可以采用多进程
- 每个进程有各自独立的 GIL,互不干扰,这样就可以真正意义上的并行执行。
在 python中,多进程的执行效率优于多线程 (仅仅针对多核 CPU而言 )。所以在多核 CPU下,想做并行提升效率,比较通用的方法是使用多进程,能够有效提高执行效率
代码示例:
# 多线程 # 最后完成的线程的耗时 # [TIME MEASURE] execute function: gene_1000_field took 3840.604ms @time_measure def mult_thread(rows): # 总行数 rows = rows # 线程数 batch_size = 4 cell = math.ceil(rows / batch_size) # 处理数据生成 print('数据生成中,线程数:' + str(batch_size)) threads = [] for i in range(batch_size): starts = i * cell ends = (i + 1) * cell file = f"my_data_{str(i)}.csv" # t = threading.Thread(target=gene_1000_field_test, args=(starts, ends, file)) t = threading.Thread(target=gene_1000_field, args=(starts, ends, file)) t.start() threads.append(t) # for t in threads: # t.join()
# 多进程 # [TIME MEASURE] execute function: gene_1000_field took 1094.776ms # 执行时间和单个线程的执行时间差不多,目的达到 @time_measure def mult_process(rows): # 总行数 rows = rows # 线程数 batch_size = 4 cell = math.ceil(rows / batch_size) # 处理数据生成 print('数据生成中,线程数:' + str(batch_size)) process = [] for i in range(batch_size): starts = i * cell ends = (i + 1) * cell file = f"my_data_{str(i)}.csv" # p = Process(target=f, args=('bob',)) # p.start() # p_lst.append(p) # t = threading.Thread(target=gene_1000_field_test, args=(starts, ends, file)) p = Process(target=gene_1000_field, args=(starts, ends, file)) p.start() process.append(p)
参考文章:
- https://www.cnblogs.com/caopeiyang/p/9418897.html
- https://www.cnblogs.com/nickchen121/p/11130256.html
- 步骤1:解析源代码文本,并将其编译成字节码(bytecode)
-
Python3中的单线程带进度条和多线程下载文件代码及注意事项
2020-05-18 17:46:19批量爬虫下载时,单线程下载文件有时慢有时快。写一个多线程分块下载文件工具。网上的一些代码可能会有些奇怪的问题,用的是类全局变量打开文件但在多线程中并未加锁,会导致文件有一定几率出现大小和源文件不同,... -
多线程为什么跑的比单线程还要慢的情况分析及验证
2015-03-11 22:42:26“多个人干活比一个人干活要快,多线程并行执行也比单线程要快”这是我学习编程长期以来的想法。然而在实际的开发过程中,并不是所有情况下都是这样。先看看下面的程序(点击下载): ThreadTester是所有Tester的...2014-05-04 07:56:50cnblogs.com-Ethan Cai-点击数: 306
“多个人干活比一个人干活要快,多线程并行执行也比单线程要快”这是我学习编程长期以来的想法。然而在实际的开发过程中,并不是所有情况下都是这样。先看看下面的程序(点击下载):
ThreadTester是所有Tester的基类。所有的Tester都干的是同样一件事情,把counter增加到100000000,每次只能加1。
public abstract class ThreadTester { public const long MAX_COUNTER_NUMBER = 100000000; private long _counter = 0; //获得计数 public long GetCounter() { return this._counter; } //增加计数器 protected void IncreaseCounter() { this._counter += 1; } //启动测试 public abstract void Start(); //获得Counter从开始增加到现在的数字所耗的时间 public abstract long GetElapsedMillisecondsOfIncreaseCounter(); //测试是否正在运行 public abstract bool IsTesterRunning(); }
SingleThreadTester是单线程计数。
class SingleThreadTester :ThreadTester { private Stopwatch _aStopWatch=new Stopwatch(); public override void Start() { _aStopWatch.Start(); Thread aThread=new Thread(()=>WorkInThread()); aThread.Start(); } public override long GetElapsedMillisecondsOfIncreaseCounter() { return this._aStopWatch.ElapsedMilliseconds; } public override bool IsTesterRunning() { return _aStopWatch.IsRunning; } private void WorkInThread() { while(true) { if(this.GetCounter()>ThreadTester.MAX_COUNTER_NUMBER) { _aStopWatch.Stop(); break; } this.IncreaseCounter(); } } }
TwoThreadSwitchTester是两个线程交替计数。class TwoThreadSwitchTester : ThreadTester { private Stopwatch _aStopWatch = new Stopwatch(); private AutoResetEvent _autoResetEvent = new AutoResetEvent(false); public override void Start() { _aStopWatch.Start(); Thread aThread1 = new Thread(() => Work1InThread()); aThread1.Start(); Thread aThread2 = new Thread(() => Work2InThread()); aThread2.Start(); } public override long GetElapsedMillisecondsOfIncreaseCounter() { return this._aStopWatch.ElapsedMilliseconds; } public override bool IsTesterRunning() { return _aStopWatch.IsRunning; } private void Work1InThread() { while (true) { _autoResetEvent.WaitOne(); this.IncreaseCounter(); if (this.GetCounter() > ThreadTester.MAX_COUNTER_NUMBER) { _aStopWatch.Stop(); break; } _autoResetEvent.Set(); } } private void Work2InThread() { while (true) { _autoResetEvent.Set(); _autoResetEvent.WaitOne(); this.IncreaseCounter(); if (this.GetCounter() > ThreadTester.MAX_COUNTER_NUMBER) { _aStopWatch.Stop(); break; } } } }
MultiThreadTester可以指定线程数,多个线程争抢计数。class MultiThreadTester : ThreadTester { private Stopwatch _aStopWatch = new Stopwatch(); private readonly int _threadCount = 0; private readonly object _counterLock = newobject(); public MultiThreadTester(int threadCount) { this._threadCount = threadCount; } public override void Start() { _aStopWatch.Start(); for (int i = 0; i < _threadCount; i++) { Thread aThread = new Thread(() => WorkInThread()); aThread.Start(); } } public override long GetElapsedMillisecondsOfIncreaseCounter() { return this._aStopWatch.ElapsedMilliseconds; } public override bool IsTesterRunning() { return _aStopWatch.IsRunning; } private void WorkInThread() { while (true) { lock (_counterLock) { if (this.GetCounter() > ThreadTester.MAX_COUNTER_NUMBER) { _aStopWatch.Stop(); break; } this.IncreaseCounter(); } } } }
Program的Main函数中,根据用户的选择来决定执行哪个测试类。import java.io.Console; class Program { static void Main(string[] args) { string inputText = GetUserChoice(); while (!"4".Equals(inputText)) { ThreadTester tester = GreateThreadTesterByInputText(inputText); tester.Start(); while (true) { Console.WriteLine(GetStatusOfThreadTester(tester)); if (!tester.IsTesterRunning()) { break; } Thread.Sleep(100); } inputText = GetUserChoice(); } Console.Write("Click enter to exit..."); } private static string GetStatusOfThreadTester(ThreadTester tester) { return string.Format("[耗时{0}ms] counter = {1}, {2}", tester.GetElapsedMillisecondsOfIncreaseCounter(), tester.GetCounter(), tester.IsTesterRunning() ? "running" : "stopped"); } private static ThreadTester GreateThreadTesterByInputText(string inputText) { switch (inputText) { case"1": return new SingleThreadTester(); case"2": return new TwoThreadSwitchTester(); default: return new MultiThreadTester(100); } } private static string GetUserChoice() { Console.WriteLine(@"==Please select the option in the following list:== 1. SingleThreadTester 2. TwoThreadSwitchTester 3. MultiThreadTester 4. Exit"); string inputText = Console.ReadLine(); return inputText; } }
三个测试类,运行结果如下:Single Thread:
[耗时407ms] counter = 100000001, stopped
[耗时453ms] counter = 100000001, stopped
[耗时412ms] counter = 100000001, stoppedTwo Thread Switch:
[耗时161503ms] counter = 100000001, stopped
[耗时164508ms] counter = 100000001, stopped
[耗时164201ms] counter = 100000001, stoppedMulti Threads - 100 Threads:
[耗时3659ms] counter = 100000001, stopped
[耗时3950ms] counter = 100000001, stopped
[耗时3720ms] counter = 100000001, stoppedMulti Threads - 2 Threads:
[耗时3078ms] counter = 100000001, stopped
[耗时3160ms] counter = 100000001, stopped
[耗时3106ms] counter = 100000001, stopped什么是线程上下文切换
上下文切换的精确定义可以参考: http://www.linfo.org/context_switch.html。多任务系统往往需要同时执行多道作业。作业数往往大于机器的CPU数,然而一颗CPU同时只能执行一项任务,为了让用户感觉这些任务正在同时进行,操作系统的设计者巧妙地利用了时间片轮转的方式,CPU给每个任务都服务一定的时间,然后把当前任务的状态保存下来,在加载下一任务的状态后,继续服务下一任务。任务的状态保存及再加载,这段过程就叫做上下文切换。时间片轮转的方式使多个任务在同一颗CPU上执行变成了可能,但同时也带来了保存现场和加载现场的直接消耗。(Note. 更精确地说, 上下文切换会带来直接和间接两种因素影响程序性能的消耗. 直接消耗包括: CPU寄存器需要保存和加载, 系统调度器的代码需要执行, TLB实例需要重新加载, CPU 的pipeline需要刷掉; 间接消耗指的是多核的cache之间得共享数据, 间接消耗对于程序的影响要看线程工作区操作数据的大小).
根据上面上下文切换的定义,我们做出下面的假设:
- 之所以TwoThreadSwitchTester执行速度最慢,因为线程上下文切换的次数最多,时间主要消耗在上下文切换了,两个线程交替计数,每计数一次就要做一次线程切换。
- “Multi Threads - 100 Threads”比“Multi Threads - 2 Threads”开的线程数量要多,导致线程切换次数也比后者多,执行时间也比后者长。
由于Windows下没有像Linux下的vmstat这样的工具,这里我们使用Process Explorer看看程序执行的时候线程上线文切换的次数。
Single Thread:
计数期间,线程总共切换了580-548=32次。(548是启动程序后,初始的数值)
Two Thread Switch:
计数期间,线程总共切换了33673295-124=33673171次。(124是启动程序后,初始的数值)
Multi Threads - 100 Threads:
计数期间,线程总共切换了846-329=517次。(329是启动程序后,初始的数值)
Multi Threads - 2 Threads:
计数期间,线程总共切换了295-201=94次。(201是启动程序后,初始的数值)
从上面收集的数据来看,和我们的判断基本相符。
干活的其实是CPU,而不是线程
再想想原来学过的知识,之前一直以为线程多干活就快,简直是把学过的计算机原理都还给老师了。真正干活的不是线程,而是CPU。线程越多,干活不一定越快。
那么高并发的情况下什么时候适合单线程,什么时候适合多线程呢?
适合单线程的场景:单个线程的工作逻辑简单,而且速度非常快,比如从内存中读取某个值,或者从Hash表根据key获得某个value。Redis和Node.js这类程序都是单线程,适合单个线程简单快速的场景。
适合多线程的场景:单个线程的工作逻辑复杂,等待时间较长或者需要消耗大量系统运算资源,比如需要从多个远程服务获得数据并计算,或者图像处理。
例子程序:http://pan.baidu.com/s/1c05WrGO
参考:
- Context Switch – Wikipedia
- 多线程的代价
- Threading in C#
- 为什么我要用 Node.js? 案例逐一介绍
- 知乎——redis是个单线程的程序,为什么会这么快呢?每秒10000?这个有点不解,具体是快在哪里呢?EPOLL?内存?多线程
- 从Java视角理解系统结构(一)CPU上下文切换
如下是自己写的多线程验证代码:
1.Junit测试类 import java.io.IOException; import java.io.InputStream; import java.net.SocketException; import java.util.ArrayList; import org.apache.commons.net.ftp.FTPClient; import org.junit.Test; import com.Thread.MyThread; public class MainTest { private int count = 10000; private int countTest = 10000; //用主线程遍历ArrayList(结论:如果循环中不sleep,速度最快,如果循环中sleep,则遍历速度比多线程慢) @Test public void test() throws InterruptedException { long startTime = System.currentTimeMillis(); ArrayList<Integer> testList = new ArrayList<Integer>(); ArrayList<Integer> testList1 = new ArrayList<Integer>(); for(int i=0; i<count; i++){ testList.add(i); } for(int j=0; j<countTest; j++){ testList1.add(j); } System.out.println("testList.size():" + testList.size() + " i=" + 0); for(int j=0; j<testList.size(); j++){ Thread.sleep(2); System.out.println(Thread.currentThread().getName() + " :" + testList.get(j)); } for(int jj=0; jj<testList1.size(); jj++){ Thread.sleep(2); System.out.println(Thread.currentThread().getName() + " :" + testList.get(jj)); } System.out.println("程序总共花费时间:" + (System.currentTimeMillis()-startTime) + "毫秒"); } //在主线程中启动一个子线程去遍历ArrayList(结论:在循环中如果不sleep,遍历速度仅次于主线程,如果循环中sleep,速度与主线程遍历差不多) @Test public void test0() { long startTime = System.currentTimeMillis(); ArrayList<Integer> testList = new ArrayList<Integer>(); ArrayList<Integer> testList1 = new ArrayList<Integer>(); for(int j=0; j<countTest; j++){ testList1.add(j); } for(int i=0; i<count; i++){ testList.add(i); } System.out.println("testList.size():" + testList.size() + " i=" + 0); Runnable run0 = new MyThread(testList,0, count); Thread t0 = new Thread(run0, "Thread-0"); long startTime1 = System.currentTimeMillis(); t0.start(); System.out.println("线程启动时间:" + (System.currentTimeMillis() - startTime1)); try { t0.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("程序总共花费时间:" + (System.currentTimeMillis()-startTime) + "毫秒"); } //在主线程中启动两个子线程去遍历ArrayList(结论:如果在循环中不sleep,速度最慢,如果在循环中sleep,则遍历速度最快) @Test public void test1() { long startTime = System.currentTimeMillis(); ArrayList<Integer> testList = new ArrayList<Integer>(); ArrayList<Integer> testList1 = new ArrayList<Integer>(); for(int i=0; i<count; i++){ testList.add(i); } for(int j=0; j<countTest; j++){ testList1.add(j); } System.out.println("testList.size():" + testList.size() + " i=" + 0); Runnable run1 = new MyThread(testList,0, count/2); Thread t1 = new Thread(run1, "Thread-1"); t1.start(); Runnable run2 = new MyThread(testList,(count/2+1), count); Thread t2 = new Thread(run2, "Thread-2"); t2.start(); try { t1.join(); t2.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("程序总共花费时间:" + (System.currentTimeMillis()-startTime) + "毫秒"); } //用单线程从ftp上下载两个文件 @Test public void FileUpload() { long startTime = System.currentTimeMillis(); try { FTPClient ftp = new FTPClient(); ftp.connect("192.168.173.156", 21); ftp.login("admin", "123456"); InputStream in = ftp.retrieveFileStream("ax.java"); byte[] buffer = new byte[1024]; while((in.read(buffer))!=-1){ //System.out.println(Arrays.toString(buffer)); } in.close(); FTPClient ftp1 = new FTPClient(); ftp1.connect("192.168.173.156", 21); ftp1.login("admin", "123456"); InputStream in1 = ftp1.retrieveFileStream("ay.java"); byte[] buffer1 = new byte[1024]; while((in1.read(buffer1))!=-1){ //System.out.println(Arrays.toString(buffer)); } in1.close(); } catch (SocketException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("程序总共花费时间:" + (System.currentTimeMillis()-startTime) + "毫秒"); } //用两个线程从ftp上下载两个文件(结论:是多线程下载速度比单线程下载速度快) @Test public void FileUpload1() { long startTime = System.currentTimeMillis(); /* Runnable run1 = new MyThread("ax.java"); Thread t1 = new Thread(run1, "Thread-1"); t1.start(); Runnable run2 = new MyThread("ay.java"); Thread t2 = new Thread(run2, "Thread-2"); t2.start(); try { t1.join(); t2.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("程序总共花费时间:" + (System.currentTimeMillis()-startTime) + "毫秒");*/ } }
2、多线程实现类
package com.Thread; import java.io.IOException; import java.io.InputStream; import java.net.SocketException; import java.util.ArrayList; import java.util.Arrays; import org.apache.commons.net.ftp.FTPClient; public class MyThread implements Runnable{ private ArrayList<Integer> intList = new ArrayList<Integer>(); private int startNum; private int endNum; private String filename; public MyThread(ArrayList<Integer> intList, int startNum, int endNum) { super(); this.intList = intList; this.startNum = startNum; this.endNum = endNum; } @Override public void run() { System.out.println("线程"+Thread.currentThread().getName()+"开始启动……"); System.out.println("intList.size():" + intList.size() + " startNum=" + startNum + " endNum=" + endNum); for(int m=startNum; m<endNum;m++){ System.out.println(Thread.currentThread().getName() + " : " + intList.get(m)); try { Thread.sleep(2); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println("线程"+Thread.currentThread().getName()+"执行结束……"); /*try { FTPClient ftp = new FTPClient(); ftp.connect("192.168.173.156", 21); ftp.login("admin", "123456"); InputStream in = ftp.retrieveFileStream(filename); byte[] buffer = new byte[1024]; while((in.read(buffer))!=-1){ //System.out.println(Arrays.toString(buffer)); } in.close();*/ } /*public MyThread(String filename) { super(); this.filename = filename; }*/ }
请关注我微信公众号:
-
Java中使用多线程不能明显提高程序效率的一些原因
2021-03-14 22:38:19java中使用多线程不能明显提高程序效率的一些原因.使用多个线程来处理多任务的时候,效率肯定是有提高的.但是必须要慎用,否则容易出现问题.1.多线程主要是为了充分利用多核cpu,大内存这些资源.如果你的硬件跟不上,... -
Java 单线程复制文件和多线程复制文件的比较
2014-08-21 16:16:32Java 单线程复制文件和使用RandomAccessFile多线程复制文件的比较,对应博客地址为http://blog.csdn.net/zmichealchow/article/details/38687431 -
Python 多进程、多线程效率对比
2021-01-19 23:26:10而且由于线程之间切换的开销导致多线程往往比实际的单线程还要慢,所以在 python 中计算密集型任务通常使用多进程,因为各个进程有各自独立的 GIL,互不干扰。 而在 IO 密集型任务中,CPU 时常处于等待状态,操作... -
python多线程代码运行速度更慢-原因解析
2019-02-16 23:39:23写出了正确的多线程代码,运行速度反而比单线程慢很多,原来是由于GIL(Global Interpreter Lock)! GIL 是Cpython(Python语言的主流解释器)特有的全局解释器锁(其他解释器因为有自己的线程调度机制,所以没有GIL... -
python的多线程与单线程的效率问题
2018-11-01 15:54:29先了解下CPU的简单运行原理: 它运行速度非常快,1s内可以运行成千上万次,一个核心可以把1s切分成成千上万个时间... 再了解下单线程和多线程的区别: 先看下单进程,顾名思义,就是一条进程,类似于单向公路... -
多线程和单线程的区别和联系?
2022-02-26 11:10:492、多线程会存在线程上下文切换,会导致程序执行速度变慢,即采用一个拥有两个线程的进程执行所需 要的时间比一个线程的进程执行两次所需要的时间要多一些。 结论:即采用多线程不会提高程序的执行速度,反而会... -
多线程就一定比单线程快吗?
2019-06-24 16:55:00为什么要使用多线程? 在探讨文章题目之前,我们先来思考这样一个问题,你为什么要使用多线程?我相信很多人在遇到这个问题时会不假思索的回答出答案,因为并发快,那为什么并发快呢? 对于多核 CPU 来说,每... -
什么是单线程和多线程,单线程与多线程的区别
2019-03-15 11:23:16什么是进程? 当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源。...多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务, 也... -
Redis 是单线程还是多线程
2022-05-20 14:01:32Redis 是单线程还是多线程 我们平时看到介绍 Redis 的文章,都会说 Redis 是单线程的。但是我们学习的时候,比如 Redis 的 bgsave 命令,它的作用是在后台异步保存当前数据库的数据到磁盘,那既然是异步了,肯定是由... -
python是单线程的,多线程有意义么
2020-10-09 17:29:38经常遇到小伙伴提到python是单线程的,写代码的时候用多线程没有意义,今天与大家分享一下关于python的单线程与多线程相关理解。 首先 python是单线程的 这句话是不对的。 这里要提到一个概念:Python的全局解释器锁... -
单线程-多线程-高并发
2019-02-13 16:27:48而一个进程又是由多个线程所组成的。 什么是线程? 线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器等),但代码区是共享的, 即不同的线程可以执行同样的函数。 什么是高并发,及高... -
单线程与多线程的区别
2017-11-27 11:03:18什么是进程? 当一个程序开始运行时,它就是一个进程,进程包括...而一个进程又是由多个线程所组成的。 什么是线程? 线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器等),但代码区 -
Redis使用的是多线程还是单线程
2022-03-18 15:27:26这也是一个很热门的面试题: redis使用的是单线程还是多线程。 大家都知道redis的特点是...因为小白可能觉得多线程比单线程“高级”一些,肯定性能也会好。 正是由于这样的误解很容易产生,所以这个面试题受到了面试官 -
C#.多线程 (一)多线程(异步模式)与单线程(同步模式)的应用与区别 举例
2018-09-19 15:48:18单线程工作模式也成为同步模式。其就是在一定状态下只能做一件事情,比如我在18:00-18:30时间段可以做饭。 什么是多线程?多线程工作模式也成为异步模式。其就是在一定状态下可以做多件事情,比如我在18:00-18:30... -
多线程和单线程有什么本质区别
2017-05-26 14:09:171、多线程的产生并不是因为发明了多核...2、实际上,多线程的出现主要为了解决IO设备的读写速度往往比CPU的处理速度慢造成的单线程程序运行阻塞问题,一个极端的例子就是如果你需要用户在键盘上输入一个数据,当用户没 -
单线程和多线程的优缺点
2020-02-11 23:22:28单线程和多线程的优缺点 多线程处理的优点 同步应用程序的开发比较容易,但由于需要在上一个任务完成后才能开始新的任务,所以其效率通常比多线程应用程序低。如果完成同步任务所用的时间比预计时间长,应用程序... -
浏览器多线程和js单线程
2017-08-02 15:13:11这些问题的根源就是因为浏览器的多线程和js的单线程引起的。看本篇博客之前,应该充分理解消息队列,事件循环,同步异步任务等概念。 这些概念以前都知道,也了解多线程的概念。但是当遇到问题的时候,这些东西都被... -
JavaScript - 多线程/单线程, 同步/异步,阻塞/非阻塞, 回调函数
2018-11-28 10:45:13学习/操作 文档 Java NIO:浅析I/O模型 - Matrix海子 - 博客园 前言 Js中多线程-单线程, 同步-异步,阻塞-非阻塞, 回调函数的关系理解 //2018.12.12 提前说一句, 他们几者之间是有因果关系的. 1. 多线程/单线程 多... -
单线程比多线程快?
2020-09-26 11:32:13在使用多线程时,一定要知道一个道理:处理速度的最终决定因素是CPU、内存等,在单CPU(无论多少核)上,分配CPU资源的单位是“进程”而不是“线程”。 假设我要拷贝100万条数据,单CPU电脑,用一个进程,在单线程的... -
【Java 多线程】多线程带来的的风险-线程安全、多线程五个经典案例
2022-03-26 22:47:19日常开发中如果用到多线程编程,也一定会涉及到线程安全问题 线程安全这个问题就不太好理解 正因为如此,程序猿们才尝试发明出更多的编程模型来处理并发编程的任务 例如:多进程、多线程、actor、csp、async+await、...