今日已更新 133 条资讯 | 累计 37382 条内容
关于我们

标签:#ORM

找到 389 篇相关文章

AI 资讯

Podcast: The Human Edge: Why Brownfield Codebases Need Mob Programming, Not Just AI Vibes

Asgaut Mjølne Söderbom and Ola Hast discuss the evolution of their software engineering practices past continuous deployment and pair engineering. The conversation continues where it left off in the previous episode and focuses on the experiments in adopting Claude Code and the reasons why they consider it good for everything else, but not coding. By Asgaut Mjølne Söderbom, Ola Hast

2026-08-24 原文 →
AI 资讯

Benchmarking Zippers in Haskell

In the previous post , we explored zippers and their applications in functional programming. In this post, we benchmark their performance against a root-based approach. Two Approaches We define a simple tree data structure and the naive root-based approach for traversing and modifying the tree. data Tree = Atom ! Int ! String | Object ! Int ! ( Map String Tree ) deriving ( Show , Eq , Generic , NFData ) access :: [ String ] -> ( Tree -> Tree ) -> Tree -> Tree access [] f t = f t access ( k : ks ) f ( Object vers ts ) = Object vers $ Map . alter modifyChild k ts where modifyChild Nothing = error "Invalid path to access" modifyChild ( Just child ) = Just $ access ks f child access _ _ _ = error "Invalid path to access" Then we implement the zipper data structure and its operations for traversing and modifying the tree. data Zipper = Zipper { focus :: ! Tree , breadcrumbs :: [ Crumb ] } deriving ( Show , Eq , Generic , NFData ) type Move = Zipper -> Zipper data Crumb = Crumb { holeKey :: ! String , storedVers :: ! Int , siblings :: ! ( Map String Tree ) } deriving ( Show , Eq , Generic , NFData ) goDown :: String -> Zipper -> Zipper goDown k ( Zipper ( Object vers ts ) bs ) | ( Just child , siblings' ) <- Map . updateLookupWithKey ( \ _ _ -> Nothing ) k ts = Zipper child ( Crumb k vers siblings' : bs ) goDown k ( Zipper f _ ) = error $ "Cannot go to child '" ++ k ++ "' of tree: " ++ show f goUp :: Zipper -> Zipper goUp ( Zipper t ( Crumb key vers siblings' : bs )) = Zipper ( Object vers ( Map . insert key t siblings' )) bs goUp ( Zipper _ [] ) = error "Already at the top" Benchmark Design Each benchmark performs 100,000 operations. Three full trees are generated with the following shapes: Depth × width nodes Children per Map 5 × 16 1,118,481 16 10 × 4 1,398,101 4 20 × 2 2,097,151 2 Here, depth counts edges from the root. All three trees have exactly 1,048,576 leaves, but their shapes differ. The workloads are: Random lookup. Choose a path by selecting its depth uniform

2026-08-24 原文 →
AI 资讯

Calibration Is Bet Sizing

The last post was about making a number trustworthy. Leakage geometry, purge widths, de-overlap, a baseline that could not cheat. It ended with a minute-scale ceiling that held at 52% across seven configurations and a model family swap. This one is about what happens after you trust the number. Because a probability you are going to bet on is a different object from a probability you are going to report. The probabilities are not decorative The path-passage classifier is a three-class LightGBM. It returns p_up , p_down , p_none . Those go straight into the expected-value score that decides whether to take a trade and how big: long_score = p_up * ( B - C ) + p_down * ( - B - C ) + p_none * ( - C ) short_score = p_up * ( - B - C ) + p_down * ( B - C ) + p_none * ( - C ) B is the barrier, C the cost. Read the arithmetic. Every term is linear in a probability. Scale p_up by 1.2 and you scale the long score by very nearly 1.2. So miscalibration does not stay in the model. It becomes a bet-sizing error, in proportion, in the bins where the gate actually fires. A classifier that is right 70% of the time while claiming 90% is not 20 points wrong. It is sizing every position in that bin as though the edge were far larger than it is. Boosted trees are known for uncalibrated softmax output. I had been consuming it as if it were a probability. The audit Seven live assets. For each one, fit an Inductive Venn-Abers wrapper on the time-ordered older 80% of that model's training data, 6,988 rows, and evaluate against a 500-row uniform-random sample of the newer 20%, seed 42. The LightGBM models are reloaded from disk and left alone. Only the wrapper is fit. Measure Expected Calibration Error and log-loss, before and after. Asset ECE before → after ECE Δ Log-loss Δ BTC 0.1272 → 0.0621 -51.2% -5.5% ETH 0.1795 → 0.0298 -83.4% -11.5% SOL 0.1680 → 0.0386 -77.0% -10.6% XRP 0.2219 → 0.0645 -70.9% -17.7% ADA 0.1419 → 0.0369 -74.0% -8.0% LINK 0.1260 → 0.0737 -41.5% -1.2% LTC 0.1508 → 0.0603

2026-08-23 原文 →
AI 资讯

When Python is Too Slow

Python is a perfect language for Agile development, where requirements might change on the go. Especially if you are in a startup business, you will need to experiment and change things fast. However, Python is an interpreted language, and in certain situations you might need faster performance than what an interpreted language can provide. A common practice in these cases is using python-to-binary bindings, where the binary code is built with Rust, C++, or Go. In this article, I will explore bindings to Rust-based code. How do the bindings work The idea behind bindings is that you create a module with functions of a specific domain in a language that compiles to binary, and build it as a C-compatible dynamic library ( .so on Linux, .dylib on macOS, .dll on Windows). Then a Python wrapper is built as a Python package and installed together with the dynamic library, allowing you to import and use functions that pass control to the corresponding functions in the dynamic library. On some occasions, classes can be used instead of functions. If any parameters are complex, they must be serialized in the wrapper and passed to the dynamic library as a JSON string or as a set of individual primitive parameters. An experiment with benchmarks To try this Python-Rust communication, I vibe coded an experiment that reads a large CSV file and builds a new one with duplicates stripped out based on specified column indexes. In my test case, it was a 3 MB CSV file with data about European NGOs for the donation platform I am building, where I wanted to remove the NGOs that don't have website URLs listed. As benchmarked, the file was processed 4.3x faster with the Rust binding than directly with Python. Here is the repo to get a first glimpse into the code and structure. What is there to know about Rust A few things about Rust: Rust packages are built with Cargo, which is the equivalent of pip, virtualenv, and setuptools combined. A single package is called a crate, and it can be publi

2026-08-23 原文 →
AI 资讯

AI Agents Can Now Optimize Your Slow Java Code: A Spring Boot Workflow That Used to Need a Specialist

Last week a tweet went viral claiming that people complaining about LLM-generated bloat would "eat crow" once everything gets rewritten in hand-optimized assembly. Dan Luu, the engineer behind some of the most cited performance writing on the internet, responded with an essay titled "There's no reason for software to be slow anymore." It hit 620 points on Hacker News in about a day, and its argument should change how every Java team spends its next sprint. The core claim is simple and backed by real experiments: performance work that used to require a rare specialist can now be done by anyone who can type a few sentences. Luu quantifies it. The human-time cost of an optimization has dropped by what he calls "frequently 1000x / 10000x / 1000000x." He had an agent do workload-specific optimization of his own ripgrep usage, and launching it took about 2 minutes of his time. Jamie Brandon, a strong performance engineer, took Anthropic's public performance takehome exercise, then let Claude pick up where he left off. Claude got a much better result. Looking at the diff, Brandon said some of the agent's optimizations were things he had thought of but not gotten to, and others were, in his words, "just crazy shit that I would never try unless I was working on this for weeks." If you have spent six years writing Spring Boot services like I have, your reaction is probably the same as mine: interesting for regex engines, but what does this mean for the average enterprise Java service? The honest answer is that most of us will never need a custom JIT. But the underlying shift, that measuring and trying an optimization now costs minutes instead of days, applies directly to the slow endpoints every real codebase accumulates. This article is a practical workflow for turning an AI agent loose on a slow Spring Boot hot path without letting it ship garbage. Full disclosure up front: the numbers I cite from Luu's essay are his experiments, not mine. The workflow below is the one I no

2026-08-23 原文 →
AI 资讯

React at 1000Hz: Optimizing Real-Time Performance

The Performance Wall: Why React Isn't a Data Buffer If you’ve ever built a real-time application—a trading dashboard, a crypto ticker, or a live sensor monitor—you’ve likely hit the "React Performance Wall." You pipe your WebSocket messages directly into useState , and suddenly, your browser becomes a stuttering, unresponsive mess. The culprit is simple but often misunderstood: React is a UI library, not a data buffer. When you treat React state as the ultimate source of truth for every single byte of incoming data, you are essentially asking React to trigger a reconciliation cycle for every packet. If your backend is pushing data at 1,000Hz, you are trying to force 1,000 renders per second. Even the most optimized React app cannot handle that. You are blocking the main thread, tanking your frame rate, and leaving your users with a "lag machine." The "Death by a Thousand Cuts" Problem React’s reconciliation process is brilliant, but it is not built to trigger 1,000 times a second. Every setState call schedules a render. If you have a complex component tree, each render triggers diffing, lifecycle hooks, and DOM updates. When updates arrive faster than the browser can paint (typically 60Hz or 16.67ms per frame), you create a backlog of "long tasks." The browser’s main thread becomes so busy trying to keep up with the data stream that it ignores user interactions like clicks or scrolls. Your UI stops being a tool and starts being a bottleneck. The Architectural Shift: Decouple Ingestion from Rendering The fix isn't to optimize your components; it's to change your architecture. You need to stop letting React "know" about every single data point. At York.ie, we achieved a 40% boost in responsiveness by implementing a Dam Pattern . Instead of pushing packets directly into state, we treat the data flow like a dam: the water (data) flows in at high pressure, but we release it to the UI in controlled, manageable bursts. The Implementation Strategy Buffer Ingested Data: Use

2026-08-23 原文 →
AI 资讯

The Edge Computing Revolution: Securing and Scaling Middleware for Distributed Intelligence

Originally published on tamiz.pro . The proliferation of IoT devices, 5G networks, and real-time data processing demands has catalyzed a fundamental shift in computing paradigms: the move from centralized cloud infrastructure to distributed edge computing. This architectural evolution brings data processing and storage closer to the source of data generation, minimizing latency, conserving bandwidth, and enabling autonomous operations. However, distributing compute power across a vast, often heterogeneous network of edge nodes introduces significant complexities, particularly concerning middleware—the connective tissue enabling communication and data flow—and its inherent challenges around security and scalability. This deep-dive will explore the architectural implications of edge computing on middleware, focusing on the critical facets of security and scalability that define success or failure in this distributed landscape. Table of Contents 1. Understanding the Edge Computing Paradigm 2. The Role of Middleware in Edge Architectures 3. Middleware Security Challenges at the Edge 4. Strategies for Securing Edge Middleware 5. Scaling Middleware in Edge Environments 6. Architectural Patterns for Scalable Edge Middleware 7. Practical Considerations and Best Practices 8. Frequently Asked Questions 1. Understanding the Edge Computing Paradigm Edge computing extends the capabilities of cloud computing by bringing computation and data storage closer to the 'edge' of the network, where data is generated. This can range from industrial IoT devices, smart city sensors, retail points of sale, autonomous vehicles, and even user devices like smartphones. The primary motivations for this shift include: Reduced Latency: Processing data locally eliminates round trips to a central cloud, crucial for real-time applications like autonomous driving or industrial automation. Bandwidth Optimization: Only aggregated or pre-processed data needs to be sent to the cloud, significantly reducin

2026-08-23 原文 →
AI 资讯

Claude Prompt Caching: Why Agent Loops Miss the 20-Block Lookback

Your agent starts a run with cache_read_input_tokens at 40K and climbing. Twelve tool calls later, reads drop to zero and cache_creation_input_tokens jumps to the full conversation length — on every single turn. Nothing in your prompt changed. No timestamp, no reordered tool, no model switch. The prefix is byte-identical. You just hit the 20-block lookback window, and it is the single most expensive thing about Claude prompt caching that nobody puts in their retro. TL;DR A cache_control breakpoint searches backward through at most 20 content blocks to find an existing cache entry. One agentic turn with 11 parallel tool calls emits 22+ blocks and blows past that — the next request finds nothing and rewrites the whole prefix at 1.25x. Fix it by placing rolling breakpoints every ~15 blocks , not one marker on the last block. You get 4 breakpoints per request total; spend 1 on tools+system and rotate the other 3 through the message list. Invalidation is tiered , not all-or-nothing: tool_choice , images, and toggling thinking preserve the tools+system cache. Only tool-definition changes and model switches force a full rebuild. Changing the system prompt mid-run nukes everything downstream — unless you append a {"role": "system", ...} message to messages[] instead (Claude Opus 5, Opus 4.8, Fable 5; not Sonnet 5). input_tokens in the usage block is the uncached remainder only . Total prompt size is input_tokens + cache_creation + cache_read . Dashboards that graph input_tokens alone will show you a flat line while you burn cache writes. Why does Claude prompt caching miss in the middle of an agent loop? Because cache lookup is bounded. Prompt caching is a prefix match on exact bytes, but a breakpoint doesn't scan the entire history for a matching entry — it walks backward a limited number of content blocks. That limit is 20. If the previous request's cached block is more than 20 blocks behind your new breakpoint, the lookup fails, and the API treats your request as cold ev

2026-08-21 原文 →
AI 资讯

What's an event loop anyways?

Event loops are a paradigm for processing events different than your typical single-threaded or multi-threaded application. Your request gets broken down into async "events" that are executed in a loop to improve performance and minimize synchronization across threads. It is famously used by Node.js as the backbone of their event processing and also by several other technologies like Redis and Nginx . In this article I'll explain the reason for why this paradigm was created and what it tries to optimize. By the end you'll come out a little wiser, and know more than just "don't block the event loop" :). Motiviation - why event loops? To understand why we need event loops we will explore a simple but key example. Take this straightforward HTTP request code, which sends a request and then tries to read the response from the socket: def send_http_request_GET ( domain : str , request : str ) -> HttpResponse : socket_fd = get_socket_for_domain ( domain ) write_res = os . write ( socket_fd , request ) data = os . read ( socket_fd , 1024 ) return HttpResponse ( data ) We do two things in this call - write data out and read data in. Both of these actions will end up triggering syscalls through the kernel that write and fetch data. In terms of time spent on the CPU, this is relatively inexpensive; sending out packets takes very little time, and eventually reading the response will also take very little CPU time. The key time lost is from waiting on the server to respond to us. os.read will block this thread until the response is available, meaning that the thread cannot be used for any other processing during this time. If our service is single-threaded, this means that we can't make any requests in parallel and are stuck waiting on any previous requests to finish. But of course, most services are not single-threaded, so this isn't a huge problem? Let's continue with the example code, imagining that instead we are processing these requests with multiple threads pulling from a

2026-08-21 原文 →
AI 资讯

HTTP Caching Explained: max-age, ETag and Why Your Users Still See Last Week's CSS

📺 Prefer to watch? 90-second YouTube Short · 💬 Telegram Originally published on software-engineer-blog.com . You fixed the CSS. You deployed. You opened the site and checked it yourself — perfect. Then a customer sends a screenshot of last week's layout. Nothing is broken. No deploy failed, no CDN is lying to you, no file is corrupt. The browser is doing exactly what you told it to do, several days ago, in a header you probably never wrote by hand. This is the part of web performance that gets skipped, because caching looks like a setting rather than a contract. It is a contract. And like any contract, the interesting part is not what it gives you — it is what you can no longer do once you have signed it. Throughout this post I will use one running example: PlantPal , a small plant shop. One stylesheet ( app.css ), one logo ( logo.png ), one API endpoint ( /api/products ). The floor: a page load is not one thing Before caching means anything, you have to see what it is acting on. Loading PlantPal's homepage is not a request. It is roughly 40 separate requests — the HTML, the stylesheet, a few fonts, the logo, a dozen product images, the JavaScript bundle, the product API. Each one is a full round trip: DNS is probably warm, but you still pay connection setup, the request, the server's think time, and the bytes coming back. The numbers for a first visit: ~40 requests 1.2 MB transferred 2.1 s to a usable page Which gives us the only sentence in this post that you actually need to remember: The fastest request is the one the browser never sends. Not a faster server. Not a closer edge node. Not a smaller file. No request at all. Everything below is a way of getting closer to that. max-age: buying silence The blunt instrument is Cache-Control : HTTP / 1.1 200 OK Content-Type : text/css Cache-Control : max-age=31536000 31536000 is one year in seconds. You are telling every browser that receives this response: keep this copy and use it for a year without asking me again. O

2026-08-20 原文 →
AI 资讯

What's New in Go 1.27: A Developer's Practical Guide

Go 1.27 landed in August 2024, and while it doesn’t introduce earth-shattering changes, it polishes the language in ways that add up. If you’re maintaining production services or building new ones, these updates can save you time and headaches. Let’s cut through the noise and focus on what actually affects your code. Performance: Faster Without Changing a Line The compiler and runtime received several under-the-hood optimizations. Benchmarks show a 3-5% speedup in typical server workloads, with some microbenchmarks hitting 10%. This isn’t magic, it’s the result of better inlining decisions and reduced memory allocation overhead. The best part? You get this for free. Just recompile your existing code with Go 1.27 and measure the difference. One standout improvement is in garbage collection. The GC now handles large heaps more efficiently, which matters if you’re running services with hundreds of gigabytes of live data. Latency spikes during GC cycles should be less pronounced, though you’ll still want to monitor this in production. Language Tweaks: Small but Useful Go 1.27 introduces a few language changes that simplify common patterns. The most notable is the addition of the new built-in function clear. It works on slices, maps, and type parameters, letting you reset collections without reallocating them. This is particularly handy for pooling or reusing buffers. For slices, clear sets all elements to their zero value and truncates the slice to length zero. For maps, it removes all entries, leaving the map empty but with the same capacity. For type parameters, it behaves based on the underlying type, useful for generic code. Another small but welcome change is the ability to use //go:linkname with methods. This was previously restricted to functions, which made certain low-level optimizations awkward. Now you can link methods directly, which is useful for writing highly optimized libraries or interfacing with C code. Tooling: Better Debugging and Dependency Manageme

2026-08-20 原文 →
AI 资讯

RDS High Availability and credential rotation without downtime

I got an AWS question and implemented it to make sure that the option is correct. A critical financial application runs on RDS for PostgreSQL. The requirements are tight: 1-second RPO, 60-second RTO, and database credentials rotated every 30 days without taking the application offline. Two independent problems. Two independent solutions. Prerequisites Check these before running terraform apply : RDS Proxy availability RDS Proxy is not available on all instance types. It requires instances with at least 2 vCPUs. db.t3.micro is not supported. db.t3.medium and above work. Terraform executor permissions The IAM principal running Terraform needs, at minimum: rds:CreateDBInstance rds:CreateDBProxy rds:CreateDBProxyTargetGroup rds:RegisterDBProxyTargets rds:ModifyDBInstance iam:CreateRole iam:AttachRolePolicy iam:PutRolePolicy iam:PassRole secretsmanager:CreateSecret secretsmanager:PutSecretValue secretsmanager:RotateSecret lambda:CreateFunction lambda:AddPermission ec2:CreateSecurityGroup ec2:AuthorizeSecurityGroupIngress ec2:CreateDBSubnetGroup AdministratorAccess on the account covers all of these. Lock it down after the initial setup. VPC requirements RDS Proxy runs inside your VPC. You need at least two private subnets in different Availability Zones. The rotation Lambda also runs inside the VPC so it can reach the RDS instance directly during the credential update step. The problem Database failure recovery RPO of 1 second means almost no data loss is acceptable. RTO of 60 seconds means the application must resume within a minute of a failure. A standard single-instance RDS setup fails both requirements: there is no automatic failover, and restoring from a backup takes far longer than 60 seconds. Credential rotation Rotating credentials on a schedule sounds simple until you factor in application downtime. If you update a password and the application still holds connections authenticated with the old one, those connections fail. The rotation mechanism needs to handle

2026-08-19 原文 →
AI 资讯

Java 11 New Features and Performance Improvements: A Practical Guide (2026-08-18 18:42)

Java 11 New Features and Performance Improvements Released in September 2018, Java 11 is a Long-Term Support (LTS) release, making it one of the most important milestones since Java 8. For teams planning migrations, Java 11 offers a compelling mix of new language features, API enhancements, and under-the-hood performance improvements. In this post, we'll explore the most impactful changes and how they affect real-world applications. Why Java 11 Matters Java 11 is the first LTS release after Java 8, meaning it receives extended support and security updates. Unlike the non-LTS releases (9 and 10), it's designed for production stability, which is why many enterprises skipped straight from 8 to 11. Language and API Enhancements 1. Local-Variable Syntax for Lambda Parameters Java 10 introduced var for local variables. Java 11 extends this to lambda parameters, allowing you to apply annotations consistently. // Now valid in Java 11 list . forEach (( var item ) -> System . out . println ( item )); // Useful for annotations list . forEach (( @Nonnull var item ) -> process ( item )); 2. New String Methods The String class gained several convenient methods that reduce boilerplate. // Check if a string is blank (empty or whitespace only) " " . isBlank (); // true // Strip leading/trailing whitespace (Unicode-aware) " hello " . strip (); // "hello" " hello " . stripLeading (); // "hello " " hello " . stripTrailing (); // " hello" // Repeat a string "ab" . repeat ( 3 ); // "ababab" // Stream lines "line1\nline2" . lines (). forEach ( System . out :: println ); Note: strip() differs from trim() because it uses Character.isWhitespace() , correctly handling Unicode whitespace characters. 3. Files Read/Write Convenience Methods Reading and writing strings to files is now a one-liner. import java.nio.file.Files ; import java.nio.file.Path ; Path path = Path . of ( "example.txt" ); // Write Files . writeString ( path , "Hello, Java 11!" ); // Read String content = Files . readString (

2026-08-19 原文 →
AI 资讯

Transactions in NestJS and TypeORM without passing the EntityManager around

Transactions promise a simple guarantee: either everything commits, or nothing does. And yet, in a NestJS application with a repository layer, it is perfectly possible to run a rollback with no errors and then find a row still sitting in the database that should have disappeared with it. This is not a TypeORM or PostgreSQL bug. One of the repositories involved was never inside the transaction, because the EntityManager stopped being passed down three layers up. There was no exception, no warning, and the tests passed because that repository was mocked. This article describes how to make that class of failure impossible: the transaction opens at a single point — the controller handling the request — and repositories enlist themselves in the transaction in progress, without receiving anything as a parameter. It comes to about sixty lines built on AsyncLocalStorage . The second part is the one rarely told: three consequences of the transaction boundary, each with its fix. A network call inside the transaction holds a pooled connection and its locks for the entire wait. A failure record written in the catch is rolled back along with the very failure it was meant to document. And nesting two execute calls does not open a nested transaction but two independent ones, with the self-deadlock that allows. The problem: passing the EntityManager by hand TypeORM offers a transaction like this: await dataSource . transaction ( async ( manager ) => { await manager . getRepository ( UserModel ). save ( user ); await manager . getRepository ( UserSettingModel ). save ( settings ); }); For a small project this is the correct answer and nothing more is needed. The problem shows up once a repository layer exists. The manager is the transaction: if a repository does not use that manager, its queries run on a different connection and end up outside the transaction. Silently, with no error and no warning. The rollback simply does not revert them. So the manager has to reach the repository

2026-08-19 原文 →
AI 资讯

Building a Video Thumbnail Generator Service with Go and FFmpeg Workers

Every video card on our category grids was hotlinking a 1280x720 JPEG from a third-party CDN and then letting CSS scale it down to about 320 device-independent pixels. That is roughly 90 KB of wasted transfer per card, 24 cards per page, across eight regional page variants that each carry their own cache key. Mobile LCP on the busiest category pages sat at 4.1s, and the largest single contributor was an image we did not host, could not resize, and could not re-encode to WebP. The fix was not clever CSS. It was owning the frame. We built a small Go service that takes a source video (a partner preview MP4, or a poster frame that arrives at the wrong dimensions), pulls a representative frame with FFmpeg, encodes it at three widths in WebP, and writes the result to a content-addressed path the front end links directly. That service now feeds the same multi-region cron that runs TrendVidStream , and the generated files ride the same FTP mirror as the rest of the deploy. What follows is the part that actually mattered: the FFmpeg invocations, the Go concurrency model that keeps a 2-core build box from melting, and how a stateless Go daemon hands work to a PHP 8.4 + SQLite front end that cannot run a daemon at all. Why this is not a PHP job Our front end is PHP 8.4 on LiteSpeed shared hosting with SQLite (FTS5 for search) as the only datastore. It is a genuinely good fit for a read-heavy discovery site: no database server to babysit, page cache on disk, cron jobs pulling regional feeds every 2-7 hours depending on the site. It is a terrible fit for thumbnail extraction: Shared hosting caps max_execution_time at 180s. A cold FFmpeg decode of a 4-minute 1080p preview can burn 20-40s. Do 200 of them in one cron tick and you are wearing a hard timeout. shell_exec is frequently disabled, and when it is not, you get one process per request with no way to bound total concurrency. There is no shared memory between PHP requests, so two cron ticks racing on the same video ID will ha

2026-08-19 原文 →
AI 资讯

CDN: How Websites Serve Content Faster Globally

Imagine opening a website from India while its servers are located in the United States. You request an image. Your request travels thousands of kilometers to the server, the server processes it, and the response travels all the way back to you. It works. But what happens when millions of users around the world do the same thing? This is where a CDN (Content Delivery Network) comes in. A CDN helps websites deliver content from servers that are geographically closer to users, reducing latency, improving performance, and taking load away from the main server. In this article, we'll understand how CDNs work, why they're important, and how they're used in large-scale systems. What Is a CDN? A Content Delivery Network is a globally distributed network of servers that stores and delivers frequently requested content closer to users. Without a CDN, requests might look like this: User ↓ Main Server ↓ Content With a CDN, a distributed layer is added between users and the origin server: ┌── CDN Edge Server ── User (India) │ Origin Server ────┼── CDN Edge Server ── User (Europe) │ └── CDN Edge Server ── User (USA) The main server is called the origin server . The distributed servers are commonly called edge servers or Points of Presence (PoPs) . Why Do We Need a CDN? Without a CDN, users from different parts of the world may have to communicate with the same origin server. For example: User in India ───────┐ User in Germany ─────┤ User in USA ─────────┼──→ Origin Server User in Japan ───────┘ As traffic grows, this creates several problems: Higher latency More traffic reaching the origin Increased server load Slower image and video delivery Poor performance for users far away from the server A CDN solves this by distributing frequently requested content geographically. How Does a CDN Work? Suppose your website contains an image: /images/product.jpg A user in India requests it. Instead of immediately contacting your origin server, the request goes through the CDN: User ↓ CDN ↓

2026-08-18 原文 →
AI 资讯

How to Compress a GIF Without Losing Quality (2026 Guide)

Let's be honest about why you're here. You have a 4MB animated GIF that's slowing down a product page, bouncing back from an email attachment limit, or getting rejected by an ecommerce backend that caps images at 2MB. Or maybe a client sent you a loop that's 15MB and you need it under 1MB for a Slack header. The good news: you can usually cut a GIF's file size by 70–90% without anyone noticing the difference. The bad news? You have to stop thinking about GIFs as images and start thinking about them as video. Here's the practical guide to compressing GIFs in 2026, using only free browser-based tools. No uploads to shady servers, no software installs, just math and smart tradeoffs. Why GIFs get so big (and why your 4MB file is normal) GIF is a 1987 format. It was designed for simple graphics on dial-up internet, not for 4K animated logos. To understand why it bloats, you need one mental model: A GIF is a video pretending to be an image. Here's what happens under the hood: Limited palette: A GIF can only store 256 colors per frame. That's 8-bit color. Your screen displays millions of colors, so the GIF has to approximate. The real problem is how it stores those colors. Frame-by-frame storage: Unlike MP4, which stores only the changes between frames, a GIF stores every single frame as a full image . A 100-frame animation at 800x600px is 100 full-size images stacked on top of each other. Uncompressed data: GIF uses LZW compression, which is weak by modern standards. It works well on flat colors but fails on gradients, noise, or photographic content. A 10-second screen recording with a subtle gradient? That's a 20MB GIF waiting to happen. The math: A 500x500px, 30fps, 3-second GIF has 90 frames. Each frame is roughly 500x500x3 bytes (RGB) = 750KB raw. Before compression, that's 67.5MB of raw data. LZW might get it down to 4–8MB. That's why your file is huge. It's not a bug; it's the format being honest about its limitations. The three real levers to shrink a GIF You can't

2026-08-18 原文 →
AI 资讯

ASP.NET Core Output Caching: How to Make Web APIs Faster in .NET

ASP.NET Core Output Caching: How to Make Web APIs Faster in .NET When an API receives the same request repeatedly, performing the same database query and rebuilding the same response every time can waste valuable resources. For example, imagine this endpoint: GET /api/products If thousands of users request the same product catalog, your application might repeatedly: HTTP Request ↓ Controller ↓ Database Query ↓ Business Logic ↓ JSON Response For data that doesn't change frequently, this can create unnecessary database load. ASP.NET Core provides Output Caching to help solve this problem. Instead of executing the complete request pipeline every time, the application can temporarily store the generated response and reuse it for subsequent requests. In this tutorial, we'll look at how Output Caching works, how to configure it, how to invalidate cached responses, and when you should avoid using it. What Is Output Caching? Output caching stores the generated response from an endpoint. For example: First request ↓ GET /api/products ↓ Execute controller ↓ Query database ↓ Generate response ↓ Store response in cache Later: Second request ↓ GET /api/products ↓ Cached response ↓ Return immediately The database doesn't need to be queried again while the cached response is valid. Output Caching vs Response Caching These two concepts are often confused. Response Caching Response caching mainly relies on HTTP caching semantics and headers. Output Caching Output caching is controlled by ASP.NET Core and allows your application to decide which responses should be cached and for how long. Output caching provides more control over server-side response caching. 1. Add Output Caching Start by registering the output-cache services. var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); builder.Services.AddOutputCache(); var app = builder.Build(); app.UseOutputCache(); app.MapControllers(); app.Run(); The important pieces are: AddOutputCache() ↓ Configure cac

2026-08-17 原文 →