Both grant permissions, but they serve different purposes.
A Profile is mandatory — every user has exactly one. It defines the baseline: which login hours and IP ranges are allowed, what the default record type and page layout assignments are, and a starter set of object, field, and system permissions. Historically Salesforce used profiles for almost everything, which created profile sprawl — dozens of slightly different profiles, hard to maintain.
A Permission Set is additive — a user can have many. It is used to grant extra access on top of the profile. If five users in different profiles all need access to a custom Contracts object, you don't create five profile variants; you create one Contracts permission set and assign it to those five users. Permission Set Groups then bundle multiple permission sets into a single assignable unit, which is how Salesforce now recommends modelling job functions.
Salesforce's current direction is to keep profiles minimal — typically just login settings and record-type defaults — and put everything else in permission sets and permission set groups. Profiles are no longer being enhanced, and the long-term plan is to migrate most permissions out of them.
