Goroutines 8kb和windows OS线程1MB
作为windows用户,我知道操作系统线程消耗~1MB内存,因为默认情况下,windows为每个线程的用户模式堆栈分配1MB内存。如果操作系统线程更贪吃,那么Goroutines 8kb和windows OS线程1MB,windows,multithreading,go,threadpool,goroutine,Windows,Multithreading,Go,Threadpool,Goroutine,作为windows用户,我知道操作系统线程消耗~1MB内存,因为默认情况下,windows为每个线程的用户模式堆栈分配1MB内存。如果操作系统线程更贪吃,那么golang如何为每个goroutine使用~8kb内存。goroutine是一种虚拟线程吗 1 MiB是默认值,正如您正确指出的那样。您可以轻松选择自己的堆栈大小(但是,最小值仍然远远高于~8 kiB) 也就是说,goroutine不是线程。它们只是具有协同多任务的任务,类似于Python。goroutine本身就是实现所需的代码和数据;
golang
如何为每个goroutine
使用~8kb内存。goroutine
是一种虚拟线程吗 1 MiB是默认值,正如您正确指出的那样。您可以轻松选择自己的堆栈大小(但是,最小值仍然远远高于~8 kiB)
也就是说,goroutine不是线程。它们只是具有协同多任务的任务,类似于Python。goroutine本身就是实现所需的代码和数据;还有一个单独的调度器(在一个或多个OS线程上运行),它实际执行该代码
在伪代码中:
loop forever
take job from queue
execute job
end loop
当然,executejob
部分可能非常简单,也可能非常复杂。您可以做的最简单的事情就是执行一个给定的委托(如果您的语言支持类似的东西)。实际上,这只是一个方法调用。例如,在更复杂的场景中,也可能会有类似于恢复某种上下文、处理连续性和协作任务产出等内容
这是一种非常轻量级的方法,在进行异步编程时非常有用(这几乎是当今的一切:)。许多语言现在都支持类似的东西——Python是我在这个(“tasklets”)中看到的第一个,这是很久以前的事了。当然,在没有先发制人多线程的环境中,这几乎是默认设置
例如,在C#中,有Task
s。它们与goroutine并不完全相同,但在实践中,它们非常接近-主要区别在于Task
s使用线程池中的线程(通常),而不是单独的专用“调度程序”线程。这意味着,如果启动1000个任务,它们可能由1000个单独的线程运行;实际上,它要求您编写非常糟糕的任务
代码(例如,仅使用阻塞I/O、休眠线程、等待句柄等)。如果您使用Task
s进行异步非阻塞I/O和CPU工作,那么在实际操作中,它们与goroutines非常接近。理论有点不同:)
编辑:
为了消除一些混淆,下面是一个典型的C#异步方法的样子:
async Task<string> GetData()
{
var html = await HttpClient.GetAsync("http://www.google.com");
var parsedStructure = Parse(html);
var dbData = await DataLayer.GetSomeStuffAsync(parsedStructure.ElementId);
return dbData.First().Description;
}
异步任务GetData()
{
var html=await HttpClient.GetAsync(“http://www.google.com");
var parsedStructure=Parse(html);
var dbData=await DataLayer.GetSomeStuffAsync(parsedStructure.ElementId);
返回dbData.First().Description;
}
从GetData
方法的角度来看,整个处理是同步的——就好像根本没有使用异步方法一样。关键的区别在于,在进行“等待”时,您没有用完线程;但是忽略这一点,它几乎与编写同步阻塞代码完全相同。当然,这也适用于任何共享状态的问题。await
中的多线程问题与阻塞多线程I/O中的多线程问题没有太大区别。Task
s更容易避免,但这只是因为您拥有的工具,而不是因为Task
s所具有的任何“魔力”
在这方面与goroutines的主要区别在于Go并没有通常意义上的阻塞方法。它们不是阻塞,而是将特定的异步请求排队,并产生响应。当操作系统(以及Go中的任何其他层——我对内部工作没有深入的了解)接收到响应时,它将其发布到goroutine调度程序,而goroutine调度程序又知道“等待”响应的goroutine现在可以恢复执行了;当它实际得到一个插槽时,它将从“阻塞”调用继续,就像它真的被阻塞一样——但实际上,它与C#的wait
非常相似。没有根本的区别——C#的方法和Go的方法有很多区别,但它们并没有那么大
还要注意的是,这与旧Windows系统上使用的方法基本相同,没有先发制人的多任务——任何“阻塞”方法都只会将线程的执行返回给调度程序。当然,在这些系统上,您只有一个CPU内核,因此无法同时执行多个线程,但原理仍然相同。goroutines就是我们所说的。它们不是操作系统线程,由go调度程序负责。这就是为什么它们可以有更小的内存占用。goroutine不是线程,它们是(来自): …同一地址空间内的独立并发控制线程或goroutine 将其定义为: 它们被称为goroutines,因为现有的术语threads、corroutine、processs等等传达了不准确的含义。goroutine有一个简单的模型:它是一个与同一地址空间中的其他goroutine并发执行的函数。它是轻量级的,只需分配堆栈空间。堆栈开始时很小,所以很便宜,并通过根据需要分配(和释放)堆存储来增长 goroutine没有自己的线程。相反,多个goroutine(可能)被多路复用到相同的OS线程上,因此如果一个goroutine阻塞(例如,等待I/O或阻塞通道操作),其他goroutine将继续运行 可以使用该函数设置同时执行goroutine的实际线程数。从包装文件中引用: GOMAXPROCS变量限制可以同时执行用户级Go代码的操作系统线程数。代表Go代码在系统调用中可以阻止的线程数量没有限制;这些不计入GOMAXPROCS限制<