Chúng tôi không thể tìm thấy kết nối internet
Đang cố gắng kết nối lại
Có lỗi xảy ra!
Hãy kiên nhẫn trong khi chúng tôi khắc phục sự cố
TypeScript nhanh hơn gấp 10 lần
0:00 Hi everyone uh this is Anders Hejlsberg lead architect of the typescript project
0:05 and Technical fellow at Microsoft um today I'm here to talk about project Corsa which is our
0:10 effort to Port uh the typescript compiler and tool set to native code now since uh the inception of
0:18 typescript more than a decade ago uh typescripts been written in itself and that's brought a lot of
0:24 benefits but it's also consistently brought some challenges in particular around performance and
0:29 skill availability uh you know the JavaScript runtime platform is really optimized for UI
0:36 and browser usage and not so much for compute intensive workloads like compilers and system
0:42 level tools um when we talk to customers one of the most uh commonly reported issues that
0:49 they face is out of- memory situations you know where their projects are just getting bigger and
0:53 bigger um and we've likely reached the limit of what we can squeeze out of uh out of JavaScript
1:00 you know JavaScript comes with a bunch of overhead that you know is is troublesome at times like you
1:08 know it's a jit compiled language so there's always startup cost to jit compile your code
1:13 uh the very flexible object model with expando properties and so forth but that adds a lot of
1:19 cost you can't inline allocate stuff in structures and so forth there's no shared memory concurrency
1:25 um so all of these things mean that we leave money on the table you know um to to sort of illustrate
1:32 what I mean by that let me try to start um a full compile of uh the visual studio code project which
1:43 is about one and a half million lines of code and I'm going to start that with our existing compiler
1:48 while we while we keep talking here um so about six months ago we started an effort to evaluate
1:56 uh moving typescript to to native code um we knew that we wanted a port not a rewrite meaning
2:04 that we wanted to Port our existing compiler Lock Stock and Barrel and get all of the same semantics
2:10 in the new code base um we're now well underway with that uh it we have more than 100,000 lines
2:19 ported uh scanner parser binder are all pretty much complete uh the type Checker is about 80%
2:25 complete um and we're working on language service um at at this point we're porting to a language
2:33 called go um and some of you might ask well why not language my favorite language why not
2:41 C why not rust why not C++ we actually spent a lot of time prototyping in all of the various
2:48 platforms or all the various languages um and we found that go is the most suitable for the
2:55 particular workload that we're trying to do um it's sort of the lowest level language we can get
3:01 to that gives us full uh optimized native code support on all platforms um great control over
3:09 data layout uh the ability to have cyclic data structures and so forth it gives you automatic
3:15 memory management with a garbage collector and great access to concurrency um what I'm going to
3:22 show you now you saw that compiling Visual Studio code with our existing compiler takes about a
3:27 minute now we're going to take a look at what how long does it take with our new native code
3:32 compiler and there we go a little over 5 Seconds 5 and a half seconds so we're talking more than
3:46 10x faster here um which is quite dramatic you know that means your projects will load 10 times
3:53 faster that means your batch compiles will be 10 times faster um now let's try to look at
4:02 some code here um I said earlier that we're porting and that means that we are literally
4:09 taking file by file function by function and moving from JavaScript or typescript to to go
4:17 let's for example try to find here um Checker doget type of symbol which is uh a function
4:26 that we have uh in in the type checker and then let's look at the same function in our old code
4:34 base there and put them side by side and really you can see that this is a port this
4:46 is the same function with all the same code in all the same order but in go instead of in in
4:52 typescript um now what that means is that all of the implicit behaviors that we have in our
5:00 type Checker such as which type do we pick when there are multiple inference candidates Etc and
5:05 Etc all of the semantics will be the same all of the code will be different but the semantics are
5:11 are preserved and and that in turn means that we actually expect to fully be able to replicate the
5:17 same behavior um Let me let me try for example to introduce an error in this program here this is
5:24 actually the source code for the old typescript compiler I'm going to add an extra argument that
5:28 shouldn't be there so I'm going to switch to uh the compiler directory and now I'm going to set
5:35 off the old compiler compiling itself and now we should see an error reported uh the error that
5:42 we just introduced in in the code and sure enough there's that error now let's try it with the new
5:47 compiler um and you'll see exactly the same error reported all be it a lot faster obviously um and
5:57 that's the experience that we're going for here really is this is a pluck andplay replacement for
6:02 our old compiler now of course we're not just building a command line compiler that's one
6:10 of the one of the artifacts that that you know are part of the typescript tool set but there's
6:14 also the language service and which is arguably the more important thing so I'm going to launch
6:21 the go implementation of the language service from inside uh my visual studio project here
6:29 um let's do here and then let's launch VSS and that brings up a copy of visual studio with the
6:37 go language service now the native language service running underneath um and you'll see
6:43 that we have uh hover implemented here um we have go to definition we can navigate um
6:52 and also we have you know red squigglies from errors if I introduce an error you'll see red
6:57 squigglies here just to give an you an idea this is the visual studio code project again
7:02 which is 4,500 files 1 and A5 million lines of code let me try to restart the language
7:08 server and you just count here to see how many seconds that's going to take it's about one two
7:15 maybe 3 seconds to completely kill the language server process restart it parse all 4500 files
7:23 uh and bring up uh semantic errors for the file that I'm in that's at least five times faster
7:29 than project loads with the with the old language service so you're going to see some really nice
7:35 benefits When in in your coding uh experience now the new language service we're moving to
7:42 um the uh to use the LSP architecture that most languages service services use now um LSP predate
7:52 or typescript predates the introduction of LSP the language server uh protocol um and we've been w
7:59 for for years really to to move to that and that's what we're doing here um now that means that that
8:05 the language service isn't necessarily going to be a feature for feature Port of the old language
8:10 service it's obviously going to have all the all the basics but there are also today in this
8:15 modern world many cases where AI assisted uh capabilities are more appropriate than
8:22 than what is in our existing language Service uh especially when it comes to refactorings and so
8:27 forth so we're looking at how to how to SL and and dice that now I wanted to also talk a little bit
8:34 about how did we actually get all of this extra performance 10 10x is is pretty dramatic right
8:41 um it turns out that about half of the performance gain comes from moving to
8:49 native code the other half comes from our ability to use concurrency let me
8:54 try and illustrate this by first compiling uh doing a full compile
8:59 of of the old typescript compiler of using the old typescript compiler so so this is about 250,000
9:11 lines of code that's being uh checked and emitted uh and it takes about 7 Seconds let's now try and
9:17 compile it with uh our new compiler but let's Force the let's Force the compiler to run single
9:26 threaded and you'll see it completes in about 2 seconds so we're getting about 3 and 1 12x here
9:34 from uh from being uh Native but if we try to do it concurrent which is the default um you'll see
9:44 that we complete in less than a second uh and here we are about 8X faster um part of why it isn't 10x
9:51 here is just because there is one gigantic file in the in the called the type Checker and we can't
9:57 parallelize each file so so therefore you know that thing is going to take a little bit longer
10:04 with with projects like Visual Studio as you saw we're more than 10x typically um now it's it's
10:12 interesting that that um you know the the way the way we get there like our our our existing
10:18 compiler we've we ported the existing compiler and the existing compiler has a very functional uh uh
10:24 architecture internally you know once we pars and binding files we we have IM uh immutable ests and
10:31 then we can have multiple programs share the same a abstact syntax tree for for each file um now
10:39 in the in the new compiler here for all of our parsing binding and emit we are fully concurrent
10:46 because these are what what I often call embarrassingly parallelizable problems you know to
10:52 parse a source file basically means load it into memory build a data structure that represents the
10:57 source text uh in an abstract syntax tree um and then leave it in memory that's basic and and you
11:04 can do that for each file and if you have eight cores available you can go eight times faster
11:09 because it's completely parallel um type checking isn't quite parallelizable in in the same manner
11:17 because you know types kind of reach across multiple files um so what we do there is that
11:24 instead of running one type checker on a program we create some number of type Checkers currently
11:30 it's hardwired to be four um and then we give each of those type Checkers the same program but
11:35 tell them to check a quarter of the files and then they go off to work um and of course there's some
11:42 duplication there each each of those four type Checkers will all resolve all the the built-in
11:48 types from the standard library and so forth but most of the most of the resolution and checking
11:53 is local and so we see that we can we can get two to three times faster in the check phase at the
12:00 cost of maybe consuming 20 to 25% more memory but overall we still consume less memory than we used
12:07 to okay so at this point now that we're public with the the repo we have a uh single project
12:19 command line compiler um that's about 80% complete I would say it doesn't currently
12:25 support JavaScript and JS doc or jsx um but that's just a waypoint we are we are moving
12:31 towards completing that we have the language service underway but it's still early um we
12:37 do expect within this year to have a fully functional replacement command line compiler
12:43 that supports JS do jsx uh project references possibly incremental compile as well um a new
12:50 interprocess API such that from other languages you can talk to uh the compiler um and we are of
13:01 course looking at using this performance gain that we now have of 10x to to think about new kinds of
13:11 AI features that become possible such as you know uh immediate type checking of of a of an lm's uh
13:20 output Pro provision of semantic information in the llm prompts and and and so forth um now
13:28 I hope you you'll want you you'll go check out the new uh GitHub repo uh build it try it on your
13:33 own projects and share your experiences and if you find issues uh please share them as well thank you
0:00 Chào mọi người. Tôi là Anders Hejlsberg, kiến trúc sư trưởng của dự án TypeScript và là Technical Fellow tại Microsoft. Hôm nay, tôi sẽ giới thiệu về Project Corsa, một nỗ lực của chúng tôi nhằm chuyển trình biên dịch và bộ công cụ TypeScript sang mã gốc. Từ khi TypeScript ra đời hơn một thập kỷ trước, nó đã được viết bằng chính nó, điều này mang lại nhiều lợi ích, nhưng đồng thời cũng tạo ra những thách thức, đặc biệt là về hiệu suất và tính sẵn có của kỹ năng.
0:29 Như các bạn biết, nền tảng thời gian chạy JavaScript thực sự được tối ưu hóa cho giao diện người dùng và trình duyệt, chứ không phải cho các công việc đòi hỏi tính toán cao như trình biên dịch và các công cụ cấp hệ thống. Khi trao đổi với khách hàng, một trong những vấn đề thường gặp nhất là tình trạng hết bộ nhớ, đặc biệt khi dự án của họ ngày càng lớn.
0:53 Và có lẽ chúng ta đã đạt đến giới hạn của những gì có thể tận dụng từ JavaScript. JavaScript đi kèm với một loạt các chi phí phát sinh, đôi khi khá rắc rối. Ví dụ, nó là một ngôn ngữ được biên dịch JIT, vì vậy luôn có chi phí khởi động để biên dịch mã của bạn.
1:13 Mô hình đối tượng rất linh hoạt với các thuộc tính mở rộng, nhưng điều đó làm tăng thêm rất nhiều chi phí. Bạn không thể phân bổ nội tuyến các thứ trong cấu trúc, và không có tính đồng thời bộ nhớ dùng chung.
1:25 Vì vậy, tất cả những điều này có nghĩa là chúng ta đang bỏ lỡ cơ hội. Để minh họa rõ hơn, tôi sẽ thử bắt đầu biên dịch toàn bộ dự án Visual Studio Code, khoảng một triệu rưỡi dòng mã, bằng trình biên dịch hiện tại của chúng tôi trong khi chúng ta tiếp tục trò chuyện.
1:48 Khoảng sáu tháng trước, chúng tôi đã bắt đầu đánh giá việc chuyển TypeScript sang mã gốc. Chúng tôi muốn thực hiện chuyển đổi, không phải viết lại, nghĩa là chúng tôi muốn chuyển toàn bộ trình biên dịch hiện tại và giữ nguyên tất cả các ngữ nghĩa trong cơ sở mã mới.
2:10 Hiện tại, chúng tôi đang tiến triển tốt. Chúng tôi đã chuyển đổi hơn 100.000 dòng. Trình quét, trình phân tích cú pháp, trình liên kết đều gần như hoàn thành. Trình kiểm tra kiểu dữ liệu đã hoàn thành khoảng 80% và chúng tôi đang làm việc trên dịch vụ ngôn ngữ. Hiện tại, chúng tôi đang chuyển sang một ngôn ngữ gọi là Go.
2:33 Một số bạn có thể thắc mắc, tại sao không phải ngôn ngữ yêu thích của tôi? Tại sao không phải C? Tại sao không phải Rust? Tại sao không phải C++? Chúng tôi đã dành rất nhiều thời gian để tạo mẫu trên tất cả các nền tảng hoặc ngôn ngữ khác nhau, và chúng tôi thấy rằng Go phù hợp nhất cho khối lượng công việc cụ thể mà chúng tôi đang cố gắng thực hiện.
2:55 Nó là ngôn ngữ cấp thấp nhất mà chúng ta có thể tiếp cận để có được hỗ trợ mã gốc được tối ưu hóa đầy đủ trên tất cả các nền tảng, kiểm soát tuyệt vời đối với bố cục dữ liệu, khả năng có các cấu trúc dữ liệu tuần hoàn, v.v. Nó cung cấp khả năng quản lý bộ nhớ tự động với bộ thu gom rác và khả năng truy cập tuyệt vời vào tính đồng thời.
3:22 Bây giờ tôi sẽ cho các bạn thấy, việc biên dịch Visual Studio Code bằng trình biên dịch hiện tại của chúng tôi mất khoảng một phút. Bây giờ chúng ta sẽ xem mất bao lâu với trình biên dịch mã gốc mới của chúng tôi. Chỉ hơn 5 giây một chút, khoảng 5 giây rưỡi. Như vậy, tốc độ nhanh hơn hơn 10 lần, điều này khá ấn tượng.
3:46 Điều đó có nghĩa là các dự án của bạn sẽ tải nhanh hơn 10 lần. Các bản biên dịch hàng loạt của bạn cũng sẽ nhanh hơn 10 lần. Bây giờ, hãy xem một số mã ở đây. Tôi đã nói trước đó rằng chúng tôi đang thực hiện chuyển đổi, nghĩa là chúng tôi thực sự lấy từng tệp, từng hàm và chuyển từ JavaScript hoặc TypeScript sang Go.
4:17 Ví dụ, hãy tìm "Checker.doGetTypeOfSymbol", đây là một hàm trong trình kiểm tra kiểu dữ liệu của chúng ta, và sau đó xem hàm tương tự trong cơ sở mã cũ của chúng ta và đặt chúng cạnh nhau.
4:34 Các bạn có thể thấy rằng đây thực sự là một bản chuyển đổi. Đây là cùng một hàm với tất cả cùng một mã theo cùng một thứ tự, nhưng được viết bằng Go thay vì TypeScript.
4:52 Điều đó có nghĩa là tất cả các hành vi ngầm định mà chúng ta có trong trình kiểm tra kiểu dữ liệu, chẳng hạn như loại nào chúng ta chọn khi có nhiều ứng cử viên suy luận, tất cả các ngữ nghĩa sẽ giống nhau. Tất cả mã sẽ khác nhau, nhưng ngữ nghĩa được bảo toàn, và điều đó có nghĩa là chúng tôi thực sự mong đợi có thể sao chép đầy đủ hành vi tương tự.
5:17 Ví dụ, tôi sẽ thử tạo ra một lỗi trong chương trình này. Đây thực sự là mã nguồn cho trình biên dịch TypeScript cũ. Tôi sẽ thêm một đối số bổ sung không nên có ở đó. Sau đó, tôi sẽ chuyển sang thư mục trình biên dịch và yêu cầu trình biên dịch cũ biên dịch chính nó. Chúng ta sẽ thấy một lỗi được báo cáo, lỗi mà chúng ta vừa đưa vào mã.
5:42 Và chắc chắn rồi, lỗi đó xuất hiện. Bây giờ, hãy thử với trình biên dịch mới và bạn sẽ thấy chính xác lỗi tương tự được báo cáo, mặc dù nhanh hơn rất nhiều.
5:57 Đó là trải nghiệm mà chúng tôi đang hướng tới, một sự thay thế plug-and-play cho trình biên dịch cũ của chúng tôi. Tất nhiên, chúng tôi không chỉ xây dựng một trình biên dịch dòng lệnh. Đó chỉ là một phần của bộ công cụ TypeScript, mà còn có dịch vụ ngôn ngữ, và điều này có lẽ quan trọng hơn. Vì vậy, tôi sẽ khởi chạy
6:21 việc triển khai Go của dịch vụ ngôn ngữ từ bên trong dự án Visual Studio của tôi.
6:29 Hãy làm điều đó ở đây, và sau đó khởi chạy VSS. Nó sẽ hiển thị một bản sao của Visual Studio với dịch vụ ngôn ngữ Go hiện tại, dịch vụ ngôn ngữ gốc đang chạy bên dưới. Và bạn sẽ thấy rằng chúng tôi đã triển khai hover ở đây. Chúng tôi có go to definition. Chúng ta có thể điều hướng.
6:52 Chúng ta cũng có những dòng gạch đỏ báo lỗi. Nếu tôi tạo ra một lỗi, bạn sẽ thấy những dòng gạch đỏ ở đây. Để các bạn hình dung, đây là dự án Visual Studio Code, với 4.500 tệp và 1 triệu rưỡi dòng mã. Hãy để tôi thử khởi động lại máy chủ ngôn ngữ và các bạn hãy đếm xem mất bao nhiêu giây.
7:15 Mất khoảng một, hai, có lẽ 3 giây để tắt hoàn toàn quy trình máy chủ ngôn ngữ, khởi động lại, phân tích cú pháp tất cả 4.500 tệp và hiển thị các lỗi ngữ nghĩa cho tệp mà tôi đang mở. Điều đó nhanh hơn ít nhất năm lần so với tải dự án bằng dịch vụ ngôn ngữ cũ. Vì vậy, bạn sẽ thấy những lợi ích thực sự lớn trong trải nghiệm viết mã của mình.
7:35 Dịch vụ ngôn ngữ mới mà chúng tôi đang chuyển sang sử dụng kiến trúc LSP, kiến trúc mà hầu hết các dịch vụ ngôn ngữ hiện đang sử dụng. LSP ra đời sau TypeScript, sau giao thức máy chủ ngôn ngữ, và chúng tôi đã muốn chuyển sang đó trong nhiều năm, và đây là những gì chúng tôi đang làm.
8:05 Điều đó có nghĩa là dịch vụ ngôn ngữ không nhất thiết phải là một bản chuyển đổi tính năng cho tính năng của dịch vụ ngôn ngữ cũ. Rõ ràng là nó sẽ có tất cả những điều cơ bản, nhưng trong thế giới hiện đại ngày nay, khả năng hỗ trợ AI phù hợp hơn so với những gì có trong dịch vụ ngôn ngữ hiện tại của chúng tôi, đặc biệt là khi nói đến việc tái cấu trúc, v.v. Vì vậy, chúng tôi đang xem xét cách phân tích và chia nhỏ điều đó.
8:34 Bây giờ, tôi cũng muốn nói một chút về cách chúng tôi thực sự có được tất cả hiệu suất bổ sung này? Tốc độ nhanh hơn 10 lần là khá ấn tượng, phải không?
8:41 Hóa ra khoảng một nửa mức tăng hiệu suất đến từ việc chuyển sang mã gốc. Nửa còn lại đến từ khả năng sử dụng tính đồng thời của chúng tôi. Hãy để tôi thử minh họa điều này bằng cách biên dịch đầy đủ trình biên dịch TypeScript cũ bằng trình biên dịch TypeScript cũ.
9:11 Đây là khoảng 250.000 dòng mã đang được kiểm tra và phát ra, và mất khoảng 7 giây. Bây giờ hãy thử biên dịch nó bằng trình biên dịch mới của chúng tôi, nhưng hãy buộc trình biên dịch chạy đơn luồng. Bạn sẽ thấy nó hoàn thành trong khoảng 2 giây. Như vậy, chúng ta có được tốc độ nhanh hơn khoảng 3 lần rưỡi từ việc sử dụng mã gốc.
9:34 Nhưng nếu chúng ta cố gắng thực hiện đồng thời, đó là mặc định, bạn sẽ thấy rằng chúng ta hoàn thành trong vòng chưa đầy một giây, và ở đây chúng ta nhanh hơn khoảng 8 lần. Một phần lý do tại sao nó không phải là 10 lần là vì có một tệp khổng lồ được gọi là trình kiểm tra kiểu dữ liệu và chúng ta không thể song song hóa từng tệp. Vì vậy, điều đó sẽ mất một chút thời gian hơn.
10:04 Với các dự án như Visual Studio, như bạn đã thấy, chúng tôi thường nhanh hơn hơn 10 lần. Điều thú vị là, cách chúng ta đạt được điều đó, giống như trình biên dịch hiện tại của chúng tôi, chúng tôi đã chuyển trình biên dịch hiện tại và trình biên dịch hiện tại có một kiến trúc chức năng rất tốt bên trong.
10:24 Sau khi chúng tôi phân tích cú pháp và liên kết các tệp, chúng tôi có các AST bất biến và sau đó chúng tôi có thể có nhiều chương trình chia sẻ cùng một cây cú pháp trừu tượng cho mỗi tệp. Trong trình biên dịch mới này, cho tất cả quá trình phân tích cú pháp, liên kết và phát ra, chúng tôi hoàn toàn đồng thời vì đây là những vấn đề mà tôi thường gọi là có thể song song hóa một cách dễ dàng.
10:52 Để phân tích cú pháp một tệp nguồn về cơ bản có nghĩa là tải nó vào bộ nhớ, xây dựng một cấu trúc dữ liệu đại diện cho văn bản nguồn trong một cây cú pháp trừu tượng, và sau đó để nó trong bộ nhớ. Về cơ bản là như vậy, và bạn có thể làm điều đó cho từng tệp. Nếu bạn có tám lõi khả dụng, bạn có thể đi nhanh hơn tám lần vì nó hoàn toàn song song.
11:09 Kiểm tra kiểu dữ liệu không hoàn toàn có thể song song hóa theo cùng một cách vì các kiểu có xu hướng trải rộng trên nhiều tệp. Vì vậy, thay vì chạy một trình kiểm tra kiểu dữ liệu trên một chương trình, chúng tôi tạo ra một số trình kiểm tra kiểu dữ liệu.
11:30 Hiện tại, số lượng được cố định là bốn. Chúng tôi cung cấp cho mỗi trình kiểm tra kiểu dữ liệu đó cùng một chương trình, nhưng yêu cầu chúng kiểm tra một phần tư số tệp và sau đó chúng bắt đầu hoạt động. Tất nhiên, có một số trùng lặp ở đó. Mỗi một trong số bốn trình kiểm tra kiểu dữ liệu đó sẽ giải quyết tất cả các kiểu tích hợp từ thư viện tiêu chuẩn, v.v.
11:53 Nhưng hầu hết quá trình giải quyết và kiểm tra là cục bộ. Vì vậy, chúng tôi thấy rằng chúng tôi có thể nhanh hơn từ hai đến ba lần trong giai đoạn kiểm tra với chi phí có thể tiêu thụ thêm từ 20 đến 25% bộ nhớ, nhưng nhìn chung, chúng tôi vẫn tiêu thụ ít bộ nhớ hơn so với trước đây.
12:07 Hiện tại, chúng tôi đã công khai kho lưu trữ. Chúng tôi có một trình biên dịch dòng lệnh dự án duy nhất, hoàn thành khoảng 80%. Nó hiện không hỗ trợ JavaScript và JS doc hoặc JSX, nhưng đó chỉ là tạm thời. Chúng tôi đang tiến tới hoàn thành điều đó. Chúng tôi đang thực hiện dịch vụ ngôn ngữ, nhưng vẫn còn sớm.
12:37 Chúng tôi dự kiến trong năm nay sẽ có một trình biên dịch dòng lệnh thay thế hoàn toàn chức năng, hỗ trợ JS, JSX, tham chiếu dự án, có thể là biên dịch gia tăng, một API giữa các quy trình mới để từ các ngôn ngữ khác, bạn có thể giao tiếp với trình biên dịch.
13:01 Và tất nhiên, chúng tôi đang xem xét việc sử dụng mức tăng hiệu suất này mà chúng tôi hiện có là 10 lần để suy nghĩ về các loại tính năng AI mới có thể thực hiện được, chẳng hạn như kiểm tra kiểu dữ liệu ngay lập tức của đầu ra của LLM, cung cấp thông tin ngữ nghĩa trong lời nhắc LLM, v.v.
13:28 Hy vọng các bạn sẽ ghé thăm kho lưu trữ GitHub mới, xây dựng nó, thử nó trên các dự án của riêng bạn và chia sẻ kinh nghiệm của bạn. Nếu bạn tìm thấy vấn đề, vui lòng chia sẻ chúng. Cảm ơn bạn.
Dịch Vào Lúc: 2025-03-12T14:17:27Z
Phiên bản Dịch: 3.1 Improved translation step with full context